linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support
@ 2022-03-24  1:48 Serge Semin
  2022-03-24  1:48 ` [PATCH 01/25] dmaengine: dw-edma: Drop dma_slave_config.direction field usage Serge Semin
                   ` (24 more replies)
  0 siblings, 25 replies; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

This is a final patchset in the series created in the framework of
my Baikal-T1 PCIe/eDMA-related work:

[1: In-progress] clk: Baikal-T1 DDR/PCIe resets and some xGMAC fixes
Link: --submitted--
[2: In-progress] PCI: dwc: Various fixes and cleanups
Link: --submitted--
[3: In-progress] PCI: dwc: Add dma-ranges/YAML-schema/Baikal-T1 support
Link: --submitted--
[4: In-progress] dmaengine: dw-edma: Add RP/EP local DMA controllers support
Link: --you are looking at it--

Note it is recommended to merge the last patchset after the former ones in
order to prevent merge conflicts. @Bjorn could you merge in this patchset
through your PCIe repo? After getting all the ack'es of course.

Please note originally this series was self content, but due to Frank
being a bit faster in his work submission I had to rebase my patchset onto
his one. So now this patchset turns to be dependent on the Frank' work:
Link: https://lore.kernel.org/dmaengine/20220310192457.3090-1-Frank.Li@nxp.com/
So please review and merge his series first before applying this one.

@Frank, @Manivannan as we agreed here:
Link: https://lore.kernel.org/dmaengine/20220309211204.26050-6-Frank.Li@nxp.com/
this series contains two patches with our joint work. Here they are:
[PATCH 1/25] dmaengine: dw-edma: Drop dma_slave_config.direction field usage
[PATCH 2/25] dmaengine: dw-edma: Fix eDMA Rd/Wr-channels and DMA-direction semantics
@Frank, could you please pick them up and add them to your series in place
of the patches:
[PATCH v5 6/9] dmaengine: dw-edma: Don't rely on the deprecated "direction" member
Link: https://lore.kernel.org/dmaengine/20220310192457.3090-7-Frank.Li@nxp.com/
[PATCH v5 5/9] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
Link: https://lore.kernel.org/dmaengine/20220310192457.3090-6-Frank.Li@nxp.com/
respectively?

@Frank please don't forget to fix your series so the chip->dw field is
initialized after all the probe() initializations are done. For that sake
you also need to make sure that the dw_edma_irq_request(),
dw_edma_channel_setup() and dw_edma_v0_core_debugfs_on() methods take
dw_edma structure pointer as a parameter.

Here is a short summary regarding this patchset. The series starts with
fixes patches. The very first two patches have been modified based on
discussion with @Frank and @Manivannan as I noted in the previous
paragraph. They concern fixing the Read/Write channels xfer semantics.
See the patches description for more details. After that goes the fix of
the dma_direct_map_resource() method, which turned out to be not working
correctly for the case of having devive.dma_range_map being non-empty
(non-empty dma-ranges DT property). Then we discovered that the
dw-edma-pcie.c driver incorrectly initializes the LL/DT base addresses for
the platforms with not matching CPU and PCIe memory spaces. It is fixed by
using the pci_bus_address() method to get a correct base address. After
that you can find a series of interleaved xfers fixes. It turned out the
interleaved transfers implementation didn't work quite correctly from the
very beginning for instance missing src/dst addresses initialization, etc.
In the framework of the next two patches we suggest to add a new
platform-specific callback - pci_addrees() and use to convert the CPU
address to the PCIe space address. It is at least required for the DW eDAM
remote End-point setup on the platforms with not-matching address spaces.
In case of the DW eDMA local RP/EP setup the conversion will be done
automatically by the outbound iATU (if no DMA-bypass flag is specified for
the corresponding iATU window). Then we introduce a set of patches to make
the DebugFS part of the code supporting the multi-eDMA controllers
platforms. It starts with several cleanup patches and is closed joining
the Read/Write channels into a single DMA-device as they originally should
have been. After that you can find the patches with adding the non-atomic
io-64 methods usage, dropping DT-region descriptors allocation, replacing
chip IDs with device name. In addition to that in order to have the eDMA
embedded into the DW PCIe RP/EP supported we need to bypass the
dma-ranges-based memory ranges mapping since in case of the root port DT
node it's applicable for the peripheral PCIe devices only. Finally at the
series closure we introduce a generic DW eDMA controller support being
available in the DW PCIe Host/End-point driver.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Cc: Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>
Cc: Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>
Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Cc: Rob Herring <robh@kernel.org>
Cc: "Krzysztof Wilczyński" <kw@linux.com>
Cc: linux-pci@vger.kernel.org
Cc: dmaengine@vger.kernel.org
Cc: linux-kernel@vger.kernel.org

Serge Semin (25):
  dmaengine: dw-edma: Drop dma_slave_config.direction field usage
  dmaengine: dw-edma: Fix eDMA Rd/Wr-channels and DMA-direction
    semantics
  dma-direct: take dma-ranges/offsets into account in resource mapping
  dmaengine: Fix dma_slave_config.dst_addr description
  dmaengine: dw-edma: Convert ll/dt phys-address to PCIe bus/DMA address
  dmaengine: dw-edma: Fix missing src/dst address of the interleaved
    xfers
  dmaengine: dw-edma: Don't permit non-inc interleaved xfers
  dmaengine: dw-edma: Fix invalid interleaved xfers semantics
  dmaengine: dw-edma: Add CPU to PCIe bus address translation
  dmaengine: dw-edma: Add PCIe bus address getter to the remote EP
    glue-driver
  dmaengine: dw-edma: Drop chancnt initialization
  dmaengine: dw-edma: Fix DebugFS reg entry type
  dmaengine: dw-edma: Stop checking debugfs_create_*() return value
  dmaengine: dw-edma: Add dw_edma prefix to the DebugFS nodes descriptor
  dmaengine: dw-edma: Convert DebugFS descs to being kz-allocated
  dmaengine: dw-edma: Simplify the DebugFS context CSRs init procedure
  dmaengine: dw-edma: Move eDMA data pointer to DebugFS node descriptor
  dmaengine: dw-edma: Join Write/Read channels into a single device
  dmaengine: dw-edma: Use DMA-engine device DebugFS subdirectory
  dmaengine: dw-edma: Use non-atomic io-64 methods
  dmaengine: dw-edma: Drop DT-region allocation
  dmaengine: dw-edma: Replace chip ID number with device name
  dmaengine: dw-edma: Bypass dma-ranges mapping for the local setup
  dmaengine: dw-edma: Skip cleanup procedure if no private data found
  PCI: dwc: Add DW eDMA engine support

 drivers/dma/dw-edma/dw-edma-core.c            | 249 +++++++------
 drivers/dma/dw-edma/dw-edma-core.h            |  10 +-
 drivers/dma/dw-edma/dw-edma-pcie.c            |  24 +-
 drivers/dma/dw-edma/dw-edma-v0-core.c         |  76 ++--
 drivers/dma/dw-edma/dw-edma-v0-core.h         |   1 -
 drivers/dma/dw-edma/dw-edma-v0-debugfs.c      | 350 ++++++++----------
 drivers/dma/dw-edma/dw-edma-v0-debugfs.h      |   5 -
 .../pci/controller/dwc/pcie-designware-ep.c   |   4 +
 .../pci/controller/dwc/pcie-designware-host.c |  13 +-
 drivers/pci/controller/dwc/pcie-designware.c  | 188 ++++++++++
 drivers/pci/controller/dwc/pcie-designware.h  |  23 +-
 include/linux/dma/edma.h                      |  18 +-
 include/linux/dmaengine.h                     |   2 +-
 kernel/dma/direct.c                           |   2 +-
 14 files changed, 598 insertions(+), 367 deletions(-)

-- 
2.35.1


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

* [PATCH 01/25] dmaengine: dw-edma: Drop dma_slave_config.direction field usage
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-24 13:30   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 02/25] dmaengine: dw-edma: Fix eDMA Rd/Wr-channels and DMA-direction semantics Serge Semin
                   ` (23 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

The dma_slave_config.direction field usage in the DW eDMA driver has been
introduced in the commit bd96f1b2f43a ("dmaengine: dw-edma: support local
dma device transfer semantics"). Mainly the change introduced there was
correct (indeed DEV_TO_MEM means using RD-channel and MEM_TO_DEV -
WR-channel for the case of having eDMA accessed locally from
CPU/Application side), but providing an additional
MEM_TO_MEM/DEV_TO_DEV-based semantics was quite redundant if not to say
potentially harmful (when it comes to removing the denoted field). First
of all since the dma_slave_config.direction field has been marked as
obsolete (see [1] and the structure dc [2]) and will be discarded in
future, using it especially in a non-standard way is discouraged. Secondly
in accordance with the commit denoted above the default
dw_edma_device_transfer() semantics has been changed despite what it's
message said. So claiming that the method was left backward compatible was
wrong.

Anyway let's fix the problems denoted above and simplify the
dw_edma_device_transfer() method by dropping the parsing of the
DMA-channel direction field. Instead of having that implicit
dma_slave_config.direction field semantic we can use the recently added
DW_EDMA_CHIP_LOCAL flag to distinguish between the local and remote DW
eDMA setups thus preserving both cases support. In addition to that an
ASCII-figure has been added to clarify the complication out.

[1] Documentation/driver-api/dmaengine/provider.rst
[2] include/linux/dmaengine.h: dma_slave_config.direction

Co-developed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

---

In accordance with agreement with Frank and Manivannan this patch is
supposed to be moved to the series:
Link: https://lore.kernel.org/dmaengine/20220310192457.3090-1-Frank.Li@nxp.com/
in place of the patch:
[PATCH v5 6/9] dmaengine: dw-edma: Don't rely on the deprecated "direction" member
Link: https://lore.kernel.org/dmaengine/20220310192457.3090-7-Frank.Li@nxp.com/
---
 drivers/dma/dw-edma/dw-edma-core.c | 49 +++++++++++++++++++++---------
 1 file changed, 34 insertions(+), 15 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 5be8a5944714..e9e32ed74aa9 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -339,21 +339,40 @@ 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;
-		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;
+	/*
+	 * Local Root Port/End-point              Remote End-point
+	 * +-----------------------+ PCIe bus +----------------------+
+	 * |                       |    +-+   |                      |
+	 * |    DEV_TO_MEM   Rx Ch <----+ +---+ Tx Ch  DEV_TO_MEM    |
+	 * |                       |    | |   |                      |
+	 * |    MEM_TO_DEV   Tx Ch +----+ +---> Rx Ch  MEM_TO_DEV    |
+	 * |                       |    +-+   |                      |
+	 * +-----------------------+          +----------------------+
+	 *
+	 * 1. Normal logic:
+	 * If eDMA is embedded into the DW PCIe RP/EP and controlled from the
+	 * CPU/Application side, the Rx channel (EDMA_DIR_READ) will be used
+	 * for the device read operations (DEV_TO_MEM) and the Tx channel
+	 * (EDMA_DIR_WRITE) - for the write operations (MEM_TO_DEV).
+	 *
+	 * 2. Inverted logic:
+	 * If eDMA is embedded into a Remote PCIe EP and is controlled by the
+	 * MWr/MRd TLPs sent from the CPU's PCIe host controller, the Tx
+	 * channel (EDMA_DIR_WRITE) will be used for the device read operations
+	 * (DEV_TO_MEM) and the Rx channel (EDMA_DIR_READ) - for the write
+	 * operations (MEM_TO_DEV).
+	 *
+	 * It is the client driver responsibility to choose a proper channel
+	 * for the DMA transfers.
+	 */
+	if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
+		if ((chan->dir == EDMA_DIR_READ && dir != DMA_DEV_TO_MEM) ||
+		    (chan->dir == EDMA_DIR_WRITE && dir != DMA_MEM_TO_DEV))
+			return NULL;
+	} else {
+		if ((chan->dir == EDMA_DIR_WRITE && dir != DMA_DEV_TO_MEM) ||
+		    (chan->dir == EDMA_DIR_READ && dir != DMA_MEM_TO_DEV))
+			return NULL;
 	}
 
 	if (xfer->type == EDMA_XFER_CYCLIC) {
-- 
2.35.1


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

* [PATCH 02/25] dmaengine: dw-edma: Fix eDMA Rd/Wr-channels and DMA-direction semantics
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
  2022-03-24  1:48 ` [PATCH 01/25] dmaengine: dw-edma: Drop dma_slave_config.direction field usage Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-24  1:48 ` [PATCH 03/25] dma-direct: take dma-ranges/offsets into account in resource mapping Serge Semin
                   ` (22 subsequent siblings)
  24 siblings, 0 replies; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam, Alan Mikhak
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

In accordance with [1, 2] the DW eDMA controller has been created to be
part of the DW PCIe Root Port and DW PCIe End-point controllers and to
offload the transferring of large blocks of data between application and
remote PCIe domains leaving the system CPU free for other tasks. In the
first case (eDMA being part of DW PCIe Root Port) the eDMA controller is
always accessible via the CPU DBI interface and never over the PCIe wire.
The later case is more complex. Depending on the DW PCIe End-Point IP-core
synthesize parameters it's possible to have the eDMA registers accessible
not only from the application CPU side, but also via mapping the eDMA CSRs
over a dedicated end-point BAR. So based on the specifics denoted above
the eDMA driver is supposed to support two types of the DMA controller
setups:
1) eDMA embedded into the DW PCIe Root Port/End-point and accessible over
the local CPU from the application side.
2) eDMA embedded into the DW PCIe End-point and accessible via the PCIe
wire with MWr/MRd TLPs generated by the CPU PCIe host controller.
Since the CPU memory resides different sides in these cases the semantics
of the MEM_TO_DEV and DEV_TO_MEM operations is flipped with respect to the
Tx and Rx DMA channels. So MEM_TO_DEV/DEV_TO_MEM corresponds to the Tx/Rx
channels in setup 1) and to the Rx/Tx channels in case of setup 2).

The DW eDMA driver has supported the case 2) since the initial
commit e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver") in the
framework of the drivers/dma/dw-edma/dw-edma-pcie.c driver. The case 1)
support was added a bit later in commit bd96f1b2f43a ("dmaengine: dw-edma:
support local dma device transfer semantics"). Afterwards the driver was
supposed to cover the both possible eDMA setups, but the later commit
turned to be not fully correct. The problem was that the commit together
with the new functionality support also changed the channel direction
semantics in a way so the eDMA Read-channel (corresponding to the
DMA_DEV_TO_MEM direction for the case 1.) now uses the sgl/cyclic base
addresses as the Source addresses of the DMA-transfers and
dma_slave_config.dst_addr as the Destination address of the DMA-transfers.
Similarly the eDMA Write-channel (corresponding to the DMA_MEM_TO_DEV
direction for case 1.) now utilizes dma_slave_config.src_addr as a source
address of the DMA-transfers and sgl/cyclic base address as the
Destination address of the DMA-transfers. This contradicts to the logic of
the DMA-interface, which implies that DEV side is supposed to belong to
the PCIe device memory and MEM - to the CPU/Application memory. Indeed it
seems irrational to have the SG-list defined in the PCIe bus space, while
expecting a contiguous buffer allocated in the CPU memory. Moreover the
passed SG-list and cyclic DMA buffers are supposed to be mapped in a way
so to be seen by the DW eDMA Application (CPU) interface. So in order to
have the correct DW eDMA interface we need to invert the eDMA
Rd/Wr-channels and DMA-slave directions semantics by selecting the src/dst
addresses based on the DMA transfer direction instead of using the channel
direction capability.

[1] DesignWare Cores PCI Express Controller Databook - DWC PCIe Root Port,
v.5.40a, March 2019, p.1092
[2] DesignWare Cores PCI Express Controller Databook - DWC PCIe Endpoint,
v.5.40a, March 2019, p.1189

Fixes: bd96f1b2f43a ("dmaengine: dw-edma: support local dma device transfer semantics")
Co-developed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

---

In accordance with agreement with Frank and Manivannan this patch is
supposed to be moved to the series:
Link: https://lore.kernel.org/dmaengine/20220310192457.3090-1-Frank.Li@nxp.com/
in place of the patch:
[PATCH v5 5/9] dmaengine: dw-edma: Fix programming the source & dest addresses for ep
Link: https://lore.kernel.org/dmaengine/20220310192457.3090-6-Frank.Li@nxp.com/
---
 drivers/dma/dw-edma/dw-edma-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index e9e32ed74aa9..519d4b3c9fa0 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -442,7 +442,7 @@ 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) {
+		if (dir == DMA_DEV_TO_MEM) {
 			burst->sar = src_addr;
 			if (xfer->type == EDMA_XFER_CYCLIC) {
 				burst->dar = xfer->xfer.cyclic.paddr;
-- 
2.35.1


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

* [PATCH 03/25] dma-direct: take dma-ranges/offsets into account in resource mapping
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
  2022-03-24  1:48 ` [PATCH 01/25] dmaengine: dw-edma: Drop dma_slave_config.direction field usage Serge Semin
  2022-03-24  1:48 ` [PATCH 02/25] dmaengine: dw-edma: Fix eDMA Rd/Wr-channels and DMA-direction semantics Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-24 11:30   ` Robin Murphy
  2022-03-24  1:48 ` [PATCH 04/25] dmaengine: Fix dma_slave_config.dst_addr description Serge Semin
                   ` (21 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam, Christoph Hellwig,
	Marek Szyprowski, Robin Murphy, Vladimir Murzin
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel, iommu

A basic device-specific linear memory mapping was introduced back in
commit ("dma: Take into account dma_pfn_offset") as a single-valued offset
preserved in the device.dma_pfn_offset field, which was initialized for
instance by means of the "dma-ranges" DT property. Afterwards the
functionality was extended to support more than one device-specific region
defined in the device.dma_range_map list of maps. But all of these
improvements concerned a single pointer, page or sg DMA-mapping methods,
while the system resource mapping function turned to miss the
corresponding modification. Thus the dma_direct_map_resource() method now
just casts the CPU physical address to the device DMA address with no
dma-ranges-based mapping taking into account, which is obviously wrong.
Let's fix it by using the phys_to_dma_direct() method to get the
device-specific bus address from the passed memory resource for the case
of the directly mapped DMA.

Fixes: 25f1e1887088 ("dma: Take into account dma_pfn_offset")
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 kernel/dma/direct.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 50f48e9e4598..9ce8192b29ab 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -497,7 +497,7 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 dma_addr_t dma_direct_map_resource(struct device *dev, phys_addr_t paddr,
 		size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
-	dma_addr_t dma_addr = paddr;
+	dma_addr_t dma_addr = phys_to_dma_direct(dev, paddr);
 
 	if (unlikely(!dma_capable(dev, dma_addr, size, false))) {
 		dev_err_once(dev,
-- 
2.35.1


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

* [PATCH 04/25] dmaengine: Fix dma_slave_config.dst_addr description
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (2 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 03/25] dma-direct: take dma-ranges/offsets into account in resource mapping Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-24 14:08   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 05/25] dmaengine: dw-edma: Convert ll/dt phys-address to PCIe bus/DMA address Serge Semin
                   ` (20 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

Most likely due to a copy-paste mistake the dst_addr member of the
dma_slave_config structure has been marked as ignored if the !source!
address belong to the memory. That is relevant to the src_addr field of
the structure while the dst_addr field as containing a destination device
address is supposed to be ignored if the destination is the CPU memory.
Let's fix the field description accordingly.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 include/linux/dmaengine.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 842d4f7ca752..f204ea16ac1c 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -395,7 +395,7 @@ enum dma_slave_buswidth {
  * should be read (RX), if the source is memory this argument is
  * ignored.
  * @dst_addr: this is the physical address where DMA slave data
- * should be written (TX), if the source is memory this argument
+ * should be written (TX), if the destination is memory this argument
  * is ignored.
  * @src_addr_width: this is the width in bytes of the source (RX)
  * register where DMA data shall be read. If the source
-- 
2.35.1


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

* [PATCH 05/25] dmaengine: dw-edma: Convert ll/dt phys-address to PCIe bus/DMA address
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (3 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 04/25] dmaengine: Fix dma_slave_config.dst_addr description Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-24 16:23   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 06/25] dmaengine: dw-edma: Fix missing src/dst address of the interleaved xfers Serge Semin
                   ` (19 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel, Gustavo Pimentel

In accordance with the dw_edma_region.paddr field semantics it is supposed
to be initialized with a memory base address visible by the DW eDMA
controller. If the DMA engine is embedded into the DW PCIe Host/EP
controller, then the address should belong to the Local CPU/Application
memory. If eDMA is remotely accessible across the PCIe bus via the PCIe
memory IOs, then the address needs to be a part of the PCIe bus memory
space. The later case hasn't been well covered in the corresponding
glue-driver. Since in general the PCIe memory space doesn't have to match
the CPU memory space and the pci_dev.resource[] arrays contain the
resources defined in the CPU memory space, a proper conversion needs to be
performed, otherwise either the driver won't properly work or much worse
the memory corruption will happen. The conversion can be done by means of
the pci_bus_address() method. Let's use it to retrieve the LL, DT and CSRs
PCIe memory ranges.

Note in addition to that we need to extend the dw_edma_region.paddr field
size. The field normally contains a memory range base address to be set in
the DW eDMA Linked-List pointer register or as a base address of the
Linked-List data buffer. In accordance with [1] the LL range is supposed
to be created in the Local CPU/Application memory, but depending on the DW
eDMA utilization the memory can be created as a part of the PCIe bus
address space (as in the case of the DW PCIe EP prototype kit). Thus in
the former case the dw_edma_region.paddr field should have the dma_addr_t
type, while in the later one - pci_bus_addr_t. Seeing the corresponding
CSRs are always 64-bits wide let's convert the dw_edma_region.paddr field
type to be u64 and let the client code logic to make sure it has a valid
address visible by the DW eDMA controller. For instance the DW eDMA PCIe
glue-driver initializes the field with the addresses from the PCIe bus
memory space.

[1] DesignWare Cores PCI Express Controller Databook - DWC PCIe Root Port,
    v.5.40a, March 2019, p.1103

Fixes: 41aaff2a2ac0 ("dmaengine: Add Synopsys eDMA IP PCIe glue-logic")
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-pcie.c | 8 ++++----
 include/linux/dma/edma.h           | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index d6b5e2463884..04c95cba1244 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -231,7 +231,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			return -ENOMEM;
 
 		ll_region->vaddr += ll_block->off;
-		ll_region->paddr = pdev->resource[ll_block->bar].start;
+		ll_region->paddr = pci_bus_address(pdev, ll_block->bar);
 		ll_region->paddr += ll_block->off;
 		ll_region->sz = ll_block->sz;
 
@@ -240,7 +240,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			return -ENOMEM;
 
 		dt_region->vaddr += dt_block->off;
-		dt_region->paddr = pdev->resource[dt_block->bar].start;
+		dt_region->paddr = pci_bus_address(pdev, dt_block->bar);
 		dt_region->paddr += dt_block->off;
 		dt_region->sz = dt_block->sz;
 	}
@@ -256,7 +256,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			return -ENOMEM;
 
 		ll_region->vaddr += ll_block->off;
-		ll_region->paddr = pdev->resource[ll_block->bar].start;
+		ll_region->paddr = pci_bus_address(pdev, ll_block->bar);
 		ll_region->paddr += ll_block->off;
 		ll_region->sz = ll_block->sz;
 
@@ -265,7 +265,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			return -ENOMEM;
 
 		dt_region->vaddr += dt_block->off;
-		dt_region->paddr = pdev->resource[dt_block->bar].start;
+		dt_region->paddr = pci_bus_address(pdev, dt_block->bar);
 		dt_region->paddr += dt_block->off;
 		dt_region->sz = dt_block->sz;
 	}
diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
index 8897f8a79b52..5abac9640a4e 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -18,7 +18,7 @@
 struct dw_edma;
 
 struct dw_edma_region {
-	phys_addr_t	paddr;
+	u64		paddr;
 	void __iomem	*vaddr;
 	size_t		sz;
 };
-- 
2.35.1


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

* [PATCH 06/25] dmaengine: dw-edma: Fix missing src/dst address of the interleaved xfers
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (4 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 05/25] dmaengine: dw-edma: Convert ll/dt phys-address to PCIe bus/DMA address Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-24 16:26   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 07/25] dmaengine: dw-edma: Don't permit non-inc " Serge Semin
                   ` (18 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel, Gustavo Pimentel

The interleaved DMA transfers support was added in the commit 85e7518f42c8
("dmaengine: dw-edma: Add device_prep_interleave_dma() support"). It
seems like the support was broken from the very beginning. Depending on
the selected channel either source or destination address are left
uninitialized which was obviously wrong. I don't really know how come the
original modification was working for the commit author. Anyway let's fix
it by initializing the destination address of the eDMA burst descriptors
for the DEV_TO_MEM interleaved operations and by initializing the source
address of the eDMA burst descriptors for the MEM_TO_DEV interleaved
operations.

Fixes: 85e7518f42c8 ("dmaengine: dw-edma: Add device_prep_interleave_dma() support")
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-core.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 519d4b3c9fa0..2010d7f8191f 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -456,6 +456,8 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 				 * and destination addresses are increased
 				 * by the same portion (data length)
 				 */
+			} else if (xfer->type == EDMA_XFER_INTERLEAVED) {
+				burst->dar = dst_addr;
 			}
 		} else {
 			burst->dar = dst_addr;
@@ -471,6 +473,8 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 				 * and destination addresses are increased
 				 * by the same portion (data length)
 				 */
+			}  else if (xfer->type == EDMA_XFER_INTERLEAVED) {
+				burst->sar = src_addr;
 			}
 		}
 
-- 
2.35.1


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

* [PATCH 07/25] dmaengine: dw-edma: Don't permit non-inc interleaved xfers
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (5 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 06/25] dmaengine: dw-edma: Fix missing src/dst address of the interleaved xfers Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-24 17:15   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 08/25] dmaengine: dw-edma: Fix invalid interleaved xfers semantics Serge Semin
                   ` (17 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel, Gustavo Pimentel

DW eDMA controller always increments both source and destination
addresses. Permitting DMA interleaved transfers with no src_inc/dst_inc
flags set may lead to unexpected behaviour for the device users. Let's fix
that by terminating the interleaved transfers if at least one of the
dma_interleaved_template.{src_inc,dst_inc} flag is initialized with false
value. Note in addition to that we need we need to increase the source and
destination addresses accordingly after each iteration.

Fixes: 85e7518f42c8 ("dmaengine: dw-edma: Add device_prep_interleave_dma() support")
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-core.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 2010d7f8191f..f41bde27795c 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -386,6 +386,8 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 			return NULL;
 		if (xfer->xfer.il->numf > 0 && xfer->xfer.il->frame_size > 0)
 			return NULL;
+		if (!xfer->xfer.il->src_inc || !xfer->xfer.il->dst_inc)
+			return NULL;
 	} else {
 		return NULL;
 	}
@@ -485,15 +487,13 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 			struct dma_interleaved_template *il = xfer->xfer.il;
 			struct data_chunk *dc = &il->sgl[i];
 
-			if (il->src_sgl) {
-				src_addr += burst->sz;
+			src_addr += burst->sz;
+			if (il->src_sgl)
 				src_addr += dmaengine_get_src_icg(il, dc);
-			}
 
-			if (il->dst_sgl) {
-				dst_addr += burst->sz;
+			dst_addr += burst->sz;
+			if (il->dst_sgl)
 				dst_addr += dmaengine_get_dst_icg(il, dc);
-			}
 		}
 	}
 
-- 
2.35.1


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

* [PATCH 08/25] dmaengine: dw-edma: Fix invalid interleaved xfers semantics
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (6 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 07/25] dmaengine: dw-edma: Don't permit non-inc " Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-24  1:48 ` [PATCH 09/25] dmaengine: dw-edma: Add CPU to PCIe bus address translation Serge Semin
                   ` (16 subsequent siblings)
  24 siblings, 0 replies; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel, Gustavo Pimentel

The interleaved DMA transfer support added in commit 85e7518f42c8
("dmaengine: dw-edma: Add device_prep_interleave_dma() support") seems
contradicting to what the DMA-engine defines. The next conditional
statements:
	if (!xfer->xfer.il->numf)
		return NULL;
	if (xfer->xfer.il->numf > 0 && xfer->xfer.il->frame_size > 0)
		return NULL;
basically mean that numf can't be zero and frame_size must always be zero,
otherwise the transfer won't be executed. But further the transfer
execution method takes the frames size from the
dma_interleaved_template.sgl[] array for each frame. That array in
accordance with [1] is supposed to be of
dma_interleaved_template.frame_size size, which as we discovered before
the code expects to be zero. So judging by the dw_edma_device_transfer()
implementation the method implies the dma_interleaved_template.sgl[] array
being of dma_interleaved_template.numf size, which is wrong. Since the
dw_edma_device_transfer() method doesn't permit
dma_interleaved_template.frame_size being non-zero then actual multi-chunk
interleaved transfer turns to be unsupported even though the code implies
having it supported.

Let's fix that by adding a fully functioning support of the interleaved
DMA transfers. First of all dma_interleaved_template.frame_size is
supposed to be greater or equal to one thus having at least simple linear
chunked frames. Secondly we can create a walk-through all over the chunks
and frames just by initializing the number of the eDMA burst transactios
as a multiple of dma_interleaved_template.numf and
dma_interleaved_template.frame_size and getting the frame_size-modulo of
the iteration step as an index of the dma_interleaved_template.sgl[]
array. The rest of the dw_edma_device_transfer() method code can be left
unchanged.

[1] include/linux/dmaengine.h: doc struct dma_interleaved_template

Fixes: 85e7518f42c8 ("dmaengine: dw-edma: Add device_prep_interleave_dma() support")
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-core.c | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index f41bde27795c..97743fe44ebf 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -333,6 +333,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;
+	size_t fsz = 0;
 	u32 cnt = 0;
 	int i;
 
@@ -382,9 +383,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 		if (xfer->xfer.sg.len < 1)
 			return NULL;
 	} else if (xfer->type == EDMA_XFER_INTERLEAVED) {
-		if (!xfer->xfer.il->numf)
-			return NULL;
-		if (xfer->xfer.il->numf > 0 && xfer->xfer.il->frame_size > 0)
+		if (!xfer->xfer.il->numf || xfer->xfer.il->frame_size < 1)
 			return NULL;
 		if (!xfer->xfer.il->src_inc || !xfer->xfer.il->dst_inc)
 			return NULL;
@@ -414,10 +413,8 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 		cnt = xfer->xfer.sg.len;
 		sg = xfer->xfer.sg.sgl;
 	} else if (xfer->type == EDMA_XFER_INTERLEAVED) {
-		if (xfer->xfer.il->numf > 0)
-			cnt = xfer->xfer.il->numf;
-		else
-			cnt = xfer->xfer.il->frame_size;
+		cnt = xfer->xfer.il->numf * xfer->xfer.il->frame_size;
+		fsz = xfer->xfer.il->frame_size;
 	}
 
 	for (i = 0; i < cnt; i++) {
@@ -439,7 +436,7 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 		else if (xfer->type == EDMA_XFER_SCATTER_GATHER)
 			burst->sz = sg_dma_len(sg);
 		else if (xfer->type == EDMA_XFER_INTERLEAVED)
-			burst->sz = xfer->xfer.il->sgl[i].size;
+			burst->sz = xfer->xfer.il->sgl[i % fsz].size;
 
 		chunk->ll_region.sz += burst->sz;
 		desc->alloc_sz += burst->sz;
@@ -482,10 +479,9 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 
 		if (xfer->type == EDMA_XFER_SCATTER_GATHER) {
 			sg = sg_next(sg);
-		} else if (xfer->type == EDMA_XFER_INTERLEAVED &&
-			   xfer->xfer.il->frame_size > 0) {
+		} else if (xfer->type == EDMA_XFER_INTERLEAVED) {
 			struct dma_interleaved_template *il = xfer->xfer.il;
-			struct data_chunk *dc = &il->sgl[i];
+			struct data_chunk *dc = &il->sgl[i % fsz];
 
 			src_addr += burst->sz;
 			if (il->src_sgl)
-- 
2.35.1


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

* [PATCH 09/25] dmaengine: dw-edma: Add CPU to PCIe bus address translation
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (7 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 08/25] dmaengine: dw-edma: Fix invalid interleaved xfers semantics Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-24 17:25   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 10/25] dmaengine: dw-edma: Add PCIe bus address getter to the remote EP glue-driver Serge Semin
                   ` (15 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

Starting from commit 9575632052ba ("dmaengine: make slave address
physical") the source and destination addresses of the DMA-slave device
have been converted to being defined in CPU address space. It's DMA-device
driver responsibility to properly convert them to the reachable DMA bus
spaces. In case of the DW eDMA device, the source or destination
peripheral (slave) devices reside PCIe bus space. Thus we need to perform
the PCIe Host/EP windows-based (i.e. ranges DT-property) addresses
translation otherwise the eDMA transactions won't work as expected (or can
be even harmful) in case if the CPU and PCIe address spaces don't match.

Note 1. Even though the DMA interleaved template has both source and
destination addresses declared of dma_addr_t type only CPU memory range is
supposed to be mapped in a way so to be seen by the DMA device since it's
a subject of the DMA getting towards the system side. The device part must
not be mapped since slave device resides in the PCIe bus space, which
isn't affected by IOMMUs or iATU translations. DW PCIe eDMA generates
corresponding MWr/MRd TLPs on its own.

Note 2. This functionality is mainly required for the remote eDMA setup
since the CPU address must be manually translated into the PCIe bus space
before being written to LLI.{SAR,DAR}. If eDMA is embedded into the
locally accessible DW PCIe RP/EP software-based translation isn't required
since it will be done by hardware by means of the Outbound iATU as long as
the DMA_BYPASS flag is cleared. If the later flag is set or there is no
Outbound iATU entry found to which the SAR or DAR falls in (for Read and
Write channel respectfully), there won't be any translation performed but
DMA will proceed with the corresponding source/destination address as is.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-core.c | 18 +++++++++++++++++-
 include/linux/dma/edma.h           | 15 +++++++++++++++
 2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 97743fe44ebf..418b201fef67 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -40,6 +40,17 @@ struct dw_edma_desc *vd2dw_edma_desc(struct virt_dma_desc *vd)
 	return container_of(vd, struct dw_edma_desc, vd);
 }
 
+static inline
+u64 dw_edma_get_pci_address(struct dw_edma_chan *chan, phys_addr_t cpu_addr)
+{
+	struct dw_edma_chip *chip = chan->dw->chip;
+
+	if (chip->ops->pci_address)
+		return chip->ops->pci_address(chip->dev, cpu_addr);
+
+	return cpu_addr;
+}
+
 static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
 {
 	struct dw_edma_burst *burst;
@@ -328,11 +339,11 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 {
 	struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan);
 	enum dma_transfer_direction dir = xfer->direction;
-	phys_addr_t src_addr, dst_addr;
 	struct scatterlist *sg = NULL;
 	struct dw_edma_chunk *chunk;
 	struct dw_edma_burst *burst;
 	struct dw_edma_desc *desc;
+	u64 src_addr, dst_addr;
 	size_t fsz = 0;
 	u32 cnt = 0;
 	int i;
@@ -407,6 +418,11 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
 		dst_addr = chan->config.dst_addr;
 	}
 
+	if (dir == DMA_DEV_TO_MEM)
+		src_addr = dw_edma_get_pci_address(chan, (phys_addr_t)src_addr);
+	else
+		dst_addr = dw_edma_get_pci_address(chan, (phys_addr_t)dst_addr);
+
 	if (xfer->type == EDMA_XFER_CYCLIC) {
 		cnt = xfer->xfer.cyclic.cnt;
 	} else if (xfer->type == EDMA_XFER_SCATTER_GATHER) {
diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
index 5abac9640a4e..5cc87cfdd685 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -23,8 +23,23 @@ struct dw_edma_region {
 	size_t		sz;
 };
 
+/**
+ * struct dw_edma_core_ops - platform-specific eDMA methods
+ * @irq_vector:		Get IRQ number of the passed eDMA channel. Note the
+ *                      method accepts the channel id in the end-to-end
+ *                      numbering with the eDMA write channels being placed
+ *                      first in the row.
+ * @pci_address:	Get PCIe bus address corresponding to the passed CPU
+ *			address. Note there is no need in specifying this
+ *			function if the address translation is performed by
+ *			the DW PCIe RP/EP controller with the DW eDMA device in
+ *			subject and DMA_BYPASS isn't set for all the outbound
+ *			iATU windows. That will be done by the controller
+ *			automatically.
+ */
 struct dw_edma_core_ops {
 	int (*irq_vector)(struct device *dev, unsigned int nr);
+	u64 (*pci_address)(struct device *dev, phys_addr_t cpu_addr);
 };
 
 enum dw_edma_map_format {
-- 
2.35.1


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

* [PATCH 10/25] dmaengine: dw-edma: Add PCIe bus address getter to the remote EP glue-driver
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (8 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 09/25] dmaengine: dw-edma: Add CPU to PCIe bus address translation Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-24 17:41   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 11/25] dmaengine: dw-edma: Drop chancnt initialization Serge Semin
                   ` (14 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel, Gustavo Pimentel

In general the Synopsys PCIe EndPoint IP prototype kit can be attached to
a PCIe bus with any PCIe Host controller including to the one with
distinctive from CPU address space. Due to that we need to make sure that
the source and destination addresses of the DMA-slave devices are properly
converted to the PCIe bus address space, otherwise the DMA transaction
will not only work as expected, but may cause the memory corruption with
subsequent system crash. Let's do that by introducing a new
dw_edma_pcie_address() method defined in the dw-edma-pcie.c, which will
perform the denoted translation by using the pcibios_resource_to_bus()
method.

Fixes: 41aaff2a2ac0 ("dmaengine: Add Synopsys eDMA IP PCIe glue-logic")
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

---

Note this patch depends on the patch "dmaengine: dw-edma: Add CPU to PCIe
bus address translation" from this series.
---
 drivers/dma/dw-edma/dw-edma-pcie.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index 04c95cba1244..f530bacfd716 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -95,8 +95,23 @@ static int dw_edma_pcie_irq_vector(struct device *dev, unsigned int nr)
 	return pci_irq_vector(to_pci_dev(dev), nr);
 }
 
+static u64 dw_edma_pcie_address(struct device *dev, phys_addr_t cpu_addr)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct pci_bus_region region;
+	struct resource res = {
+		.flags = IORESOURCE_MEM,
+		.start = cpu_addr,
+		.end = cpu_addr,
+	};
+
+	pcibios_resource_to_bus(pdev->bus, &region, &res);
+	return region.start;
+}
+
 static const struct dw_edma_core_ops dw_edma_pcie_core_ops = {
 	.irq_vector = dw_edma_pcie_irq_vector,
+	.pci_address = dw_edma_pcie_address,
 };
 
 static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
-- 
2.35.1


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

* [PATCH 11/25] dmaengine: dw-edma: Drop chancnt initialization
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (9 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 10/25] dmaengine: dw-edma: Add PCIe bus address getter to the remote EP glue-driver Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-24 17:42   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 12/25] dmaengine: dw-edma: Fix DebugFS reg entry type Serge Semin
                   ` (13 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel, Gustavo Pimentel

DMA device drivers aren't supposed to initialize the dma_device.chancnt
field. It will be done by the DMA-engine core in accordance with number of
added virtual DMA-channels. Pre-initializing it with some value causes
having a wrong number of channels printed in the device summary.

Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-core.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 418b201fef67..cefa73412bf7 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -823,7 +823,6 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
 	dma->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
 	dma->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
 	dma->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
-	dma->chancnt = cnt;
 
 	/* Set DMA channel callbacks */
 	dma->dev = chip->dev;
-- 
2.35.1


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

* [PATCH 12/25] dmaengine: dw-edma: Fix DebugFS reg entry type
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (10 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 11/25] dmaengine: dw-edma: Drop chancnt initialization Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-24 17:48   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 13/25] dmaengine: dw-edma: Stop checking debugfs_create_*() return value Serge Semin
                   ` (12 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel, Gustavo Pimentel

debugfs_entries structure declared in the dw-edma-v0-debugfs.c module
contains the DebugFS node' register address. The address is declared as
dma_addr_t type, but first it's assigned with virtual CPU IOMEM address
and then it's cast back to the virtual address. Even though the castes
sandwich will unlikely cause any problem since normally DMA address is at
least of the same size as the CPU virtual address, it's at the very least
redundant if not to say logically incorrect. Let's fix it by just stop
casting the pointer back and worth and just preserve the address as a
pointer to void with __iomem qualifier.

Fixes: 305aebeff879 ("dmaengine: Add Synopsys eDMA IP version 0 debugfs support")
Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
index 3a899f7f4e8d..12845a2dc016 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
@@ -14,7 +14,7 @@
 #include "dw-edma-core.h"
 
 #define REGS_ADDR(name) \
-	((void __force *)&regs->name)
+	((void __iomem *)&regs->name)
 #define REGISTER(name) \
 	{ #name, REGS_ADDR(name) }
 
@@ -48,12 +48,13 @@ static struct {
 
 struct debugfs_entries {
 	const char				*name;
-	dma_addr_t				*reg;
+	void __iomem				*reg;
 };
 
 static int dw_edma_debugfs_u32_get(void *data, u64 *val)
 {
-	void __iomem *reg = (void __force __iomem *)data;
+	void __iomem *reg = data;
+
 	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
 	    reg >= (void __iomem *)&regs->type.legacy.ch) {
 		void __iomem *ptr = &regs->type.legacy.ch;
-- 
2.35.1


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

* [PATCH 13/25] dmaengine: dw-edma: Stop checking debugfs_create_*() return value
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (11 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 12/25] dmaengine: dw-edma: Fix DebugFS reg entry type Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-24 18:12   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 14/25] dmaengine: dw-edma: Add dw_edma prefix to the DebugFS nodes descriptor Serge Semin
                   ` (11 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

First of all they never return NULL. So checking their return value for
being not NULL just pointless. Secondly the DebugFS subsystem is designed
in a way to be used as simple as possible. So if one of the
debugfs_create_*() method in a hierarchy fails, the following methods will
just silently return the passed erroneous parental dentry. Finally the
code is supposed to be working no matter whether anything DebugFS-related
fails. So in order to make code simpler and DebugFS-independent let's drop
the debugfs_create_*() methods return value checking in the same way as
the most of the kernel drivers do.

Note in order to preserve some memory space we suggest to skip the DebugFS
nodes initialization if the file system in unavailable.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 20 +++++---------------
 1 file changed, 5 insertions(+), 15 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
index 12845a2dc016..808eed212be8 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
@@ -100,9 +100,8 @@ static void dw_edma_debugfs_create_x32(const struct debugfs_entries entries[],
 	int i;
 
 	for (i = 0; i < nr_entries; i++) {
-		if (!debugfs_create_file_unsafe(entries[i].name, 0444, dir,
-						entries[i].reg,	&fops_x32))
-			break;
+		debugfs_create_file_unsafe(entries[i].name, 0444, dir,
+					   entries[i].reg, &fops_x32);
 	}
 }
 
@@ -168,8 +167,6 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
 	char name[16];
 
 	regs_dir = debugfs_create_dir(WRITE_STR, dir);
-	if (!regs_dir)
-		return;
 
 	nr_entries = ARRAY_SIZE(debugfs_regs);
 	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
@@ -184,8 +181,6 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
 		snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
 
 		ch_dir = debugfs_create_dir(name, regs_dir);
-		if (!ch_dir)
-			return;
 
 		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].wr, ch_dir);
 
@@ -237,8 +232,6 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
 	char name[16];
 
 	regs_dir = debugfs_create_dir(READ_STR, dir);
-	if (!regs_dir)
-		return;
 
 	nr_entries = ARRAY_SIZE(debugfs_regs);
 	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
@@ -253,8 +246,6 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
 		snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
 
 		ch_dir = debugfs_create_dir(name, regs_dir);
-		if (!ch_dir)
-			return;
 
 		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].rd, ch_dir);
 
@@ -273,8 +264,6 @@ static void dw_edma_debugfs_regs(void)
 	int nr_entries;
 
 	regs_dir = debugfs_create_dir(REGISTERS_STR, dw->debugfs);
-	if (!regs_dir)
-		return;
 
 	nr_entries = ARRAY_SIZE(debugfs_regs);
 	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
@@ -285,6 +274,9 @@ static void dw_edma_debugfs_regs(void)
 
 void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
 {
+	if (!debugfs_initialized())
+		return;
+
 	dw = chip->dw;
 	if (!dw)
 		return;
@@ -294,8 +286,6 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
 		return;
 
 	dw->debugfs = debugfs_create_dir(dw->name, NULL);
-	if (!dw->debugfs)
-		return;
 
 	debugfs_create_u32("mf", 0444, dw->debugfs, &dw->chip->mf);
 	debugfs_create_u16("wr_ch_cnt", 0444, dw->debugfs, &dw->wr_ch_cnt);
-- 
2.35.1


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

* [PATCH 14/25] dmaengine: dw-edma: Add dw_edma prefix to the DebugFS nodes descriptor
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (12 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 13/25] dmaengine: dw-edma: Stop checking debugfs_create_*() return value Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-24 18:14   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 15/25] dmaengine: dw-edma: Convert DebugFS descs to being kz-allocated Serge Semin
                   ` (10 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

The rest of the locally defined and used methods and structures have
dw_edma prefix in their names. It's right in accordance with the kernel
coding style to follow the locally defined rule of naming. Let's add that
prefix to the debugfs_entries structure too especially seeing it's name
may be confusing as if that structure belongs to the global DebugFS space.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
index 808eed212be8..afd519d9568b 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
@@ -46,7 +46,7 @@ static struct {
 	void					__iomem *end;
 } lim[2][EDMA_V0_MAX_NR_CH];
 
-struct debugfs_entries {
+struct dw_edma_debugfs_entry {
 	const char				*name;
 	void __iomem				*reg;
 };
@@ -94,7 +94,7 @@ static int dw_edma_debugfs_u32_get(void *data, u64 *val)
 }
 DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");
 
-static void dw_edma_debugfs_create_x32(const struct debugfs_entries entries[],
+static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry entries[],
 				       int nr_entries, struct dentry *dir)
 {
 	int i;
@@ -108,8 +108,7 @@ static void dw_edma_debugfs_create_x32(const struct debugfs_entries entries[],
 static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs __iomem *regs,
 				    struct dentry *dir)
 {
-	int nr_entries;
-	const struct debugfs_entries debugfs_regs[] = {
+	const struct dw_edma_debugfs_entry debugfs_regs[] = {
 		REGISTER(ch_control1),
 		REGISTER(ch_control2),
 		REGISTER(transfer_size),
@@ -120,6 +119,7 @@ static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs __iomem *regs,
 		REGISTER(llp.lsb),
 		REGISTER(llp.msb),
 	};
+	int nr_entries;
 
 	nr_entries = ARRAY_SIZE(debugfs_regs);
 	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, dir);
@@ -127,7 +127,7 @@ static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs __iomem *regs,
 
 static void dw_edma_debugfs_regs_wr(struct dentry *dir)
 {
-	const struct debugfs_entries debugfs_regs[] = {
+	const struct dw_edma_debugfs_entry debugfs_regs[] = {
 		/* eDMA global registers */
 		WR_REGISTER(engine_en),
 		WR_REGISTER(doorbell),
@@ -148,7 +148,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
 		WR_REGISTER(ch67_imwr_data),
 		WR_REGISTER(linked_list_err_en),
 	};
-	const struct debugfs_entries debugfs_unroll_regs[] = {
+	const struct dw_edma_debugfs_entry debugfs_unroll_regs[] = {
 		/* eDMA channel context grouping */
 		WR_REGISTER_UNROLL(engine_chgroup),
 		WR_REGISTER_UNROLL(engine_hshake_cnt.lsb),
@@ -191,7 +191,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
 
 static void dw_edma_debugfs_regs_rd(struct dentry *dir)
 {
-	const struct debugfs_entries debugfs_regs[] = {
+	const struct dw_edma_debugfs_entry debugfs_regs[] = {
 		/* eDMA global registers */
 		RD_REGISTER(engine_en),
 		RD_REGISTER(doorbell),
@@ -213,7 +213,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
 		RD_REGISTER(ch45_imwr_data),
 		RD_REGISTER(ch67_imwr_data),
 	};
-	const struct debugfs_entries debugfs_unroll_regs[] = {
+	const struct dw_edma_debugfs_entry debugfs_unroll_regs[] = {
 		/* eDMA channel context grouping */
 		RD_REGISTER_UNROLL(engine_chgroup),
 		RD_REGISTER_UNROLL(engine_hshake_cnt.lsb),
@@ -256,7 +256,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
 
 static void dw_edma_debugfs_regs(void)
 {
-	const struct debugfs_entries debugfs_regs[] = {
+	const struct dw_edma_debugfs_entry debugfs_regs[] = {
 		REGISTER(ctrl_data_arb_prior),
 		REGISTER(ctrl),
 	};
-- 
2.35.1


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

* [PATCH 15/25] dmaengine: dw-edma: Convert DebugFS descs to being kz-allocated
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (13 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 14/25] dmaengine: dw-edma: Add dw_edma prefix to the DebugFS nodes descriptor Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-25  6:03   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 16/25] dmaengine: dw-edma: Simplify the DebugFS context CSRs init procedure Serge Semin
                   ` (9 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

Currently all the DW eDMA DebugFS nodes descriptors are allocated on
stack, while the DW eDMA driver private data and CSR limits are statically
preserved. Such design won't work for the multi-eDMA platforms. As a
preparation to adding the multi-eDMA system setups support we need to have
each DebugFS node separately allocated and described. Afterwards we'll put
an addition info there like Read/Write channel flag, channel ID, DW eDMA
private data reference.

Note this conversion is mainly required due to having the legacy DW eDMA
controllers with indirect Read/Write channels context CSRs access. If we
didn't need to have a synchronized access to these registers the DebugFS
code of the driver would have been much simpler.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
index afd519d9568b..7eb0147912fa 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
@@ -53,7 +53,8 @@ struct dw_edma_debugfs_entry {
 
 static int dw_edma_debugfs_u32_get(void *data, u64 *val)
 {
-	void __iomem *reg = data;
+	struct dw_edma_debugfs_entry __iomem *entry = data;
+	void __iomem *reg = entry->reg;
 
 	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
 	    reg >= (void __iomem *)&regs->type.legacy.ch) {
@@ -94,14 +95,22 @@ static int dw_edma_debugfs_u32_get(void *data, u64 *val)
 }
 DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");
 
-static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry entries[],
+static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry ini[],
 				       int nr_entries, struct dentry *dir)
 {
+	struct dw_edma_debugfs_entry *entries;
 	int i;
 
+	entries = devm_kcalloc(dw->chip->dev, nr_entries, sizeof(*entries),
+			       GFP_KERNEL);
+	if (!entries)
+		return;
+
 	for (i = 0; i < nr_entries; i++) {
+		entries[i] = ini[i];
+
 		debugfs_create_file_unsafe(entries[i].name, 0444, dir,
-					   entries[i].reg, &fops_x32);
+					   &entries[i], &fops_x32);
 	}
 }
 
-- 
2.35.1


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

* [PATCH 16/25] dmaengine: dw-edma: Simplify the DebugFS context CSRs init procedure
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (14 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 15/25] dmaengine: dw-edma: Convert DebugFS descs to being kz-allocated Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-25  6:27   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 17/25] dmaengine: dw-edma: Move eDMA data pointer to DebugFS node descriptor Serge Semin
                   ` (8 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

DW eDMA v4.70a and older have the read and write channels context CSRs
indirectly accessible. It means the CSRs like Channel Control, Xfer size,
SAR, DAR and LLP address are accessed over at a fixed MMIO address, but
their reference to the corresponding channel is determined by the Viewport
CSR. In order to have a coherent access to these registers the CSR IOs are
supposed to be protected with a spin-lock. DW eDMA v4.80a and newer
normally have unrolled Read/Write channel context registers. That is all
CSRs denoted before are directly mapped in the controller MMIO space.

Since both normal and viewport-based registers are exposed via the DebugFS
nodes, the original code author decided to implement an algorithm based on
the unrolled CSRs mapping with the viewport addresses recalculation if
it's required. The problem is that such implementation turned to be first
unscalable (supports a platform with only single eDMA available since a
base address statically preserved) and second needlessly overcomplicated
(it loops over all Rd/Wr context addresses and re-calculates the viewport
base address on each DebugFS node access). The algorithm can be greatly
simplified just by adding the channel ID and it's direction fields in the
eDMA DebugFS node descriptor. These new parameters can be used to find a
CSR offset within the corresponding channel registers space. The DW eDMA
DebugFS node getter afterwards will also use them in order to activate the
respective context CSRs viewport before reading data from the specified
register. In case of the unrolled version of the CSRs mapping there won't
be any spin-lock taken/released, no viewport activation as before this
modification.

Note this modification fixes the REGISTER() macros using an externally
defined local variable. The same problem with the rest of the macro will
be fixed in the next commit.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 84 +++++++++++-------------
 1 file changed, 38 insertions(+), 46 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
index 7eb0147912fa..b34a68964232 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
@@ -15,9 +15,27 @@
 
 #define REGS_ADDR(name) \
 	((void __iomem *)&regs->name)
+
+#define REGS_CH_ADDR(name, _dir, _ch)						\
+	({									\
+		struct dw_edma_v0_ch_regs __iomem *__ch_regs;			\
+										\
+		if ((dw)->chip->mf == EDMA_MF_EDMA_LEGACY)			\
+			__ch_regs = &regs->type.legacy.ch;			\
+		else if (_dir == EDMA_DIR_READ)					\
+			__ch_regs = &regs->type.unroll.ch[_ch].rd;		\
+		else								\
+			__ch_regs = &regs->type.unroll.ch[_ch].wr;		\
+										\
+		(void __iomem *)&__ch_regs->name;				\
+	})
+
 #define REGISTER(name) \
 	{ #name, REGS_ADDR(name) }
 
+#define CTX_REGISTER(name, dir, ch) \
+	{ #name, REGS_CH_ADDR(name, dir, ch), dir, ch }
+
 #define WR_REGISTER(name) \
 	{ #name, REGS_ADDR(wr_##name) }
 #define RD_REGISTER(name) \
@@ -41,14 +59,11 @@
 static struct dw_edma				*dw;
 static struct dw_edma_v0_regs			__iomem *regs;
 
-static struct {
-	void					__iomem *start;
-	void					__iomem *end;
-} lim[2][EDMA_V0_MAX_NR_CH];
-
 struct dw_edma_debugfs_entry {
 	const char				*name;
 	void __iomem				*reg;
+	enum dw_edma_dir			dir;
+	u16					ch;
 };
 
 static int dw_edma_debugfs_u32_get(void *data, u64 *val)
@@ -58,33 +73,16 @@ static int dw_edma_debugfs_u32_get(void *data, u64 *val)
 
 	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;
 		unsigned long flags;
-		u16 ch;
-
-		for (ch = 0; ch < dw->wr_ch_cnt; ch++)
-			if (lim[0][ch].start >= reg && reg < lim[0][ch].end) {
-				ptr += (reg - lim[0][ch].start);
-				goto legacy_sel_wr;
-			}
-
-		for (ch = 0; ch < dw->rd_ch_cnt; ch++)
-			if (lim[1][ch].start >= reg && reg < lim[1][ch].end) {
-				ptr += (reg - lim[1][ch].start);
-				goto legacy_sel_rd;
-			}
-
-		return 0;
-legacy_sel_rd:
-		viewport_sel = BIT(31);
-legacy_sel_wr:
-		viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
+		u32 viewport_sel;
+
+		viewport_sel = entry->dir == EDMA_DIR_READ ? BIT(31) : 0;
+		viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, entry->ch);
 
 		raw_spin_lock_irqsave(&dw->lock, flags);
 
 		writel(viewport_sel, &regs->type.legacy.viewport_sel);
-		*val = readl(ptr);
+		*val = readl(reg);
 
 		raw_spin_unlock_irqrestore(&dw->lock, flags);
 	} else {
@@ -114,19 +112,19 @@ static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry ini[],
 	}
 }
 
-static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs __iomem *regs,
+static void dw_edma_debugfs_regs_ch(enum dw_edma_dir edma_dir, u16 ch,
 				    struct dentry *dir)
 {
-	const struct dw_edma_debugfs_entry debugfs_regs[] = {
-		REGISTER(ch_control1),
-		REGISTER(ch_control2),
-		REGISTER(transfer_size),
-		REGISTER(sar.lsb),
-		REGISTER(sar.msb),
-		REGISTER(dar.lsb),
-		REGISTER(dar.msb),
-		REGISTER(llp.lsb),
-		REGISTER(llp.msb),
+	struct dw_edma_debugfs_entry debugfs_regs[] = {
+		CTX_REGISTER(ch_control1, edma_dir, ch),
+		CTX_REGISTER(ch_control2, edma_dir, ch),
+		CTX_REGISTER(transfer_size, edma_dir, ch),
+		CTX_REGISTER(sar.lsb, edma_dir, ch),
+		CTX_REGISTER(sar.msb, edma_dir, ch),
+		CTX_REGISTER(dar.lsb, edma_dir, ch),
+		CTX_REGISTER(dar.msb, edma_dir, ch),
+		CTX_REGISTER(llp.lsb, edma_dir, ch),
+		CTX_REGISTER(llp.msb, edma_dir, ch),
 	};
 	int nr_entries;
 
@@ -191,10 +189,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
 
 		ch_dir = debugfs_create_dir(name, regs_dir);
 
-		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].wr, ch_dir);
-
-		lim[0][i].start = &regs->type.unroll.ch[i].wr;
-		lim[0][i].end = &regs->type.unroll.ch[i].padding_1[0];
+		dw_edma_debugfs_regs_ch(EDMA_DIR_WRITE, i, ch_dir);
 	}
 }
 
@@ -256,10 +251,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
 
 		ch_dir = debugfs_create_dir(name, regs_dir);
 
-		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].rd, ch_dir);
-
-		lim[1][i].start = &regs->type.unroll.ch[i].rd;
-		lim[1][i].end = &regs->type.unroll.ch[i].padding_2[0];
+		dw_edma_debugfs_regs_ch(EDMA_DIR_READ, i, ch_dir);
 	}
 }
 
-- 
2.35.1


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

* [PATCH 17/25] dmaengine: dw-edma: Move eDMA data pointer to DebugFS node descriptor
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (15 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 16/25] dmaengine: dw-edma: Simplify the DebugFS context CSRs init procedure Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-25  6:35   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 18/25] dmaengine: dw-edma: Join Write/Read channels into a single device Serge Semin
                   ` (7 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

The last thing that really stops the DebugFS part of the eDMA driver from
supporting the multi-eDMA platform in is keeping the eDMA private data
pointer in the static area of the DebugFS module. Since the DebugFS node
descriptors are now kz-allocated we can freely move that pointer to being
preserved in the descriptors. After the DebugFS initialization procedure
that pointer will be used in the DebugFS files getter to access the common
CSRs space and the context CSRs spin-lock. So the main part of this change
is connected with the DebugFS nodes descriptors initialization macros,
which aside with already defined prototypes now require to have the DW
eDMA private data pointer passed.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 240 +++++++++++------------
 1 file changed, 118 insertions(+), 122 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
index b34a68964232..353269a3680b 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
@@ -13,53 +13,55 @@
 #include "dw-edma-v0-regs.h"
 #include "dw-edma-core.h"
 
-#define REGS_ADDR(name) \
-	((void __iomem *)&regs->name)
+#define REGS_ADDR(dw, name)							\
+	({									\
+		struct dw_edma_v0_regs __iomem *__regs = (dw)->chip->reg_base;	\
+										\
+		(void __iomem *)&__regs->name;					\
+	})
 
-#define REGS_CH_ADDR(name, _dir, _ch)						\
+#define REGS_CH_ADDR(dw, name, _dir, _ch)					\
 	({									\
 		struct dw_edma_v0_ch_regs __iomem *__ch_regs;			\
 										\
 		if ((dw)->chip->mf == EDMA_MF_EDMA_LEGACY)			\
-			__ch_regs = &regs->type.legacy.ch;			\
+			__ch_regs = REGS_ADDR(dw, type.legacy.ch);		\
 		else if (_dir == EDMA_DIR_READ)					\
-			__ch_regs = &regs->type.unroll.ch[_ch].rd;		\
+			__ch_regs = REGS_ADDR(dw, type.unroll.ch[_ch].rd);	\
 		else								\
-			__ch_regs = &regs->type.unroll.ch[_ch].wr;		\
+			__ch_regs = REGS_ADDR(dw, type.unroll.ch[_ch].wr);	\
 										\
 		(void __iomem *)&__ch_regs->name;				\
 	})
 
-#define REGISTER(name) \
-	{ #name, REGS_ADDR(name) }
+#define REGISTER(dw, name) \
+	{ dw, #name, REGS_ADDR(dw, name) }
 
-#define CTX_REGISTER(name, dir, ch) \
-	{ #name, REGS_CH_ADDR(name, dir, ch), dir, ch }
+#define CTX_REGISTER(dw, name, dir, ch) \
+	{ dw, #name, REGS_CH_ADDR(dw, name, dir, ch), dir, ch }
 
-#define WR_REGISTER(name) \
-	{ #name, REGS_ADDR(wr_##name) }
-#define RD_REGISTER(name) \
-	{ #name, REGS_ADDR(rd_##name) }
+#define WR_REGISTER(dw, name) \
+	{ dw, #name, REGS_ADDR(dw, wr_##name) }
+#define RD_REGISTER(dw, name) \
+	{ dw, #name, REGS_ADDR(dw, rd_##name) }
 
-#define WR_REGISTER_LEGACY(name) \
-	{ #name, REGS_ADDR(type.legacy.wr_##name) }
+#define WR_REGISTER_LEGACY(dw, name) \
+	{ dw, #name, REGS_ADDR(dw, type.legacy.wr_##name) }
 #define RD_REGISTER_LEGACY(name) \
-	{ #name, REGS_ADDR(type.legacy.rd_##name) }
+	{ dw, #name, REGS_ADDR(dw, type.legacy.rd_##name) }
 
-#define WR_REGISTER_UNROLL(name) \
-	{ #name, REGS_ADDR(type.unroll.wr_##name) }
-#define RD_REGISTER_UNROLL(name) \
-	{ #name, REGS_ADDR(type.unroll.rd_##name) }
+#define WR_REGISTER_UNROLL(dw, name) \
+	{ dw, #name, REGS_ADDR(dw, type.unroll.wr_##name) }
+#define RD_REGISTER_UNROLL(dw, name) \
+	{ dw, #name, REGS_ADDR(dw, type.unroll.rd_##name) }
 
 #define WRITE_STR				"write"
 #define READ_STR				"read"
 #define CHANNEL_STR				"channel"
 #define REGISTERS_STR				"registers"
 
-static struct dw_edma				*dw;
-static struct dw_edma_v0_regs			__iomem *regs;
-
 struct dw_edma_debugfs_entry {
+	struct dw_edma				*dw;
 	const char				*name;
 	void __iomem				*reg;
 	enum dw_edma_dir			dir;
@@ -69,10 +71,11 @@ struct dw_edma_debugfs_entry {
 static int dw_edma_debugfs_u32_get(void *data, u64 *val)
 {
 	struct dw_edma_debugfs_entry __iomem *entry = data;
+	struct dw_edma *dw = entry->dw;
 	void __iomem *reg = entry->reg;
 
 	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
-	    reg >= (void __iomem *)&regs->type.legacy.ch) {
+	    reg >= REGS_ADDR(dw, type.legacy.ch)) {
 		unsigned long flags;
 		u32 viewport_sel;
 
@@ -81,7 +84,7 @@ static int dw_edma_debugfs_u32_get(void *data, u64 *val)
 
 		raw_spin_lock_irqsave(&dw->lock, flags);
 
-		writel(viewport_sel, &regs->type.legacy.viewport_sel);
+		writel(viewport_sel, REGS_ADDR(dw, type.legacy.viewport_sel));
 		*val = readl(reg);
 
 		raw_spin_unlock_irqrestore(&dw->lock, flags);
@@ -93,7 +96,8 @@ static int dw_edma_debugfs_u32_get(void *data, u64 *val)
 }
 DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");
 
-static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry ini[],
+static void dw_edma_debugfs_create_x32(struct dw_edma *dw,
+				       const struct dw_edma_debugfs_entry ini[],
 				       int nr_entries, struct dentry *dir)
 {
 	struct dw_edma_debugfs_entry *entries;
@@ -112,62 +116,62 @@ static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry ini[],
 	}
 }
 
-static void dw_edma_debugfs_regs_ch(enum dw_edma_dir edma_dir, u16 ch,
-				    struct dentry *dir)
+static void dw_edma_debugfs_regs_ch(struct dw_edma *dw, enum dw_edma_dir edma_dir,
+				    u16 ch, struct dentry *dir)
 {
 	struct dw_edma_debugfs_entry debugfs_regs[] = {
-		CTX_REGISTER(ch_control1, edma_dir, ch),
-		CTX_REGISTER(ch_control2, edma_dir, ch),
-		CTX_REGISTER(transfer_size, edma_dir, ch),
-		CTX_REGISTER(sar.lsb, edma_dir, ch),
-		CTX_REGISTER(sar.msb, edma_dir, ch),
-		CTX_REGISTER(dar.lsb, edma_dir, ch),
-		CTX_REGISTER(dar.msb, edma_dir, ch),
-		CTX_REGISTER(llp.lsb, edma_dir, ch),
-		CTX_REGISTER(llp.msb, edma_dir, ch),
+		CTX_REGISTER(dw, ch_control1, edma_dir, ch),
+		CTX_REGISTER(dw, ch_control2, edma_dir, ch),
+		CTX_REGISTER(dw, transfer_size, edma_dir, ch),
+		CTX_REGISTER(dw, sar.lsb, edma_dir, ch),
+		CTX_REGISTER(dw, sar.msb, edma_dir, ch),
+		CTX_REGISTER(dw, dar.lsb, edma_dir, ch),
+		CTX_REGISTER(dw, dar.msb, edma_dir, ch),
+		CTX_REGISTER(dw, llp.lsb, edma_dir, ch),
+		CTX_REGISTER(dw, llp.msb, edma_dir, ch),
 	};
 	int nr_entries;
 
 	nr_entries = ARRAY_SIZE(debugfs_regs);
-	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, dir);
+	dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, dir);
 }
 
-static void dw_edma_debugfs_regs_wr(struct dentry *dir)
+static void dw_edma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dir)
 {
 	const struct dw_edma_debugfs_entry debugfs_regs[] = {
 		/* eDMA global registers */
-		WR_REGISTER(engine_en),
-		WR_REGISTER(doorbell),
-		WR_REGISTER(ch_arb_weight.lsb),
-		WR_REGISTER(ch_arb_weight.msb),
+		WR_REGISTER(dw, engine_en),
+		WR_REGISTER(dw, doorbell),
+		WR_REGISTER(dw, ch_arb_weight.lsb),
+		WR_REGISTER(dw, ch_arb_weight.msb),
 		/* eDMA interrupts registers */
-		WR_REGISTER(int_status),
-		WR_REGISTER(int_mask),
-		WR_REGISTER(int_clear),
-		WR_REGISTER(err_status),
-		WR_REGISTER(done_imwr.lsb),
-		WR_REGISTER(done_imwr.msb),
-		WR_REGISTER(abort_imwr.lsb),
-		WR_REGISTER(abort_imwr.msb),
-		WR_REGISTER(ch01_imwr_data),
-		WR_REGISTER(ch23_imwr_data),
-		WR_REGISTER(ch45_imwr_data),
-		WR_REGISTER(ch67_imwr_data),
-		WR_REGISTER(linked_list_err_en),
+		WR_REGISTER(dw, int_status),
+		WR_REGISTER(dw, int_mask),
+		WR_REGISTER(dw, int_clear),
+		WR_REGISTER(dw, err_status),
+		WR_REGISTER(dw, done_imwr.lsb),
+		WR_REGISTER(dw, done_imwr.msb),
+		WR_REGISTER(dw, abort_imwr.lsb),
+		WR_REGISTER(dw, abort_imwr.msb),
+		WR_REGISTER(dw, ch01_imwr_data),
+		WR_REGISTER(dw, ch23_imwr_data),
+		WR_REGISTER(dw, ch45_imwr_data),
+		WR_REGISTER(dw, ch67_imwr_data),
+		WR_REGISTER(dw, linked_list_err_en),
 	};
 	const struct dw_edma_debugfs_entry debugfs_unroll_regs[] = {
 		/* eDMA channel context grouping */
-		WR_REGISTER_UNROLL(engine_chgroup),
-		WR_REGISTER_UNROLL(engine_hshake_cnt.lsb),
-		WR_REGISTER_UNROLL(engine_hshake_cnt.msb),
-		WR_REGISTER_UNROLL(ch0_pwr_en),
-		WR_REGISTER_UNROLL(ch1_pwr_en),
-		WR_REGISTER_UNROLL(ch2_pwr_en),
-		WR_REGISTER_UNROLL(ch3_pwr_en),
-		WR_REGISTER_UNROLL(ch4_pwr_en),
-		WR_REGISTER_UNROLL(ch5_pwr_en),
-		WR_REGISTER_UNROLL(ch6_pwr_en),
-		WR_REGISTER_UNROLL(ch7_pwr_en),
+		WR_REGISTER_UNROLL(dw, engine_chgroup),
+		WR_REGISTER_UNROLL(dw, engine_hshake_cnt.lsb),
+		WR_REGISTER_UNROLL(dw, engine_hshake_cnt.msb),
+		WR_REGISTER_UNROLL(dw, ch0_pwr_en),
+		WR_REGISTER_UNROLL(dw, ch1_pwr_en),
+		WR_REGISTER_UNROLL(dw, ch2_pwr_en),
+		WR_REGISTER_UNROLL(dw, ch3_pwr_en),
+		WR_REGISTER_UNROLL(dw, ch4_pwr_en),
+		WR_REGISTER_UNROLL(dw, ch5_pwr_en),
+		WR_REGISTER_UNROLL(dw, ch6_pwr_en),
+		WR_REGISTER_UNROLL(dw, ch7_pwr_en),
 	};
 	struct dentry *regs_dir, *ch_dir;
 	int nr_entries, i;
@@ -176,11 +180,11 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
 	regs_dir = debugfs_create_dir(WRITE_STR, dir);
 
 	nr_entries = ARRAY_SIZE(debugfs_regs);
-	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
+	dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dir);
 
 	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,
+		dw_edma_debugfs_create_x32(dw, debugfs_unroll_regs, nr_entries,
 					   regs_dir);
 	}
 
@@ -189,47 +193,47 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
 
 		ch_dir = debugfs_create_dir(name, regs_dir);
 
-		dw_edma_debugfs_regs_ch(EDMA_DIR_WRITE, i, ch_dir);
+		dw_edma_debugfs_regs_ch(dw, EDMA_DIR_WRITE, i, ch_dir);
 	}
 }
 
-static void dw_edma_debugfs_regs_rd(struct dentry *dir)
+static void dw_edma_debugfs_regs_rd(struct dw_edma *dw, struct dentry *dir)
 {
 	const struct dw_edma_debugfs_entry debugfs_regs[] = {
 		/* eDMA global registers */
-		RD_REGISTER(engine_en),
-		RD_REGISTER(doorbell),
-		RD_REGISTER(ch_arb_weight.lsb),
-		RD_REGISTER(ch_arb_weight.msb),
+		RD_REGISTER(dw, engine_en),
+		RD_REGISTER(dw, doorbell),
+		RD_REGISTER(dw, ch_arb_weight.lsb),
+		RD_REGISTER(dw, ch_arb_weight.msb),
 		/* eDMA interrupts registers */
-		RD_REGISTER(int_status),
-		RD_REGISTER(int_mask),
-		RD_REGISTER(int_clear),
-		RD_REGISTER(err_status.lsb),
-		RD_REGISTER(err_status.msb),
-		RD_REGISTER(linked_list_err_en),
-		RD_REGISTER(done_imwr.lsb),
-		RD_REGISTER(done_imwr.msb),
-		RD_REGISTER(abort_imwr.lsb),
-		RD_REGISTER(abort_imwr.msb),
-		RD_REGISTER(ch01_imwr_data),
-		RD_REGISTER(ch23_imwr_data),
-		RD_REGISTER(ch45_imwr_data),
-		RD_REGISTER(ch67_imwr_data),
+		RD_REGISTER(dw, int_status),
+		RD_REGISTER(dw, int_mask),
+		RD_REGISTER(dw, int_clear),
+		RD_REGISTER(dw, err_status.lsb),
+		RD_REGISTER(dw, err_status.msb),
+		RD_REGISTER(dw, linked_list_err_en),
+		RD_REGISTER(dw, done_imwr.lsb),
+		RD_REGISTER(dw, done_imwr.msb),
+		RD_REGISTER(dw, abort_imwr.lsb),
+		RD_REGISTER(dw, abort_imwr.msb),
+		RD_REGISTER(dw, ch01_imwr_data),
+		RD_REGISTER(dw, ch23_imwr_data),
+		RD_REGISTER(dw, ch45_imwr_data),
+		RD_REGISTER(dw, ch67_imwr_data),
 	};
 	const struct dw_edma_debugfs_entry debugfs_unroll_regs[] = {
 		/* eDMA channel context grouping */
-		RD_REGISTER_UNROLL(engine_chgroup),
-		RD_REGISTER_UNROLL(engine_hshake_cnt.lsb),
-		RD_REGISTER_UNROLL(engine_hshake_cnt.msb),
-		RD_REGISTER_UNROLL(ch0_pwr_en),
-		RD_REGISTER_UNROLL(ch1_pwr_en),
-		RD_REGISTER_UNROLL(ch2_pwr_en),
-		RD_REGISTER_UNROLL(ch3_pwr_en),
-		RD_REGISTER_UNROLL(ch4_pwr_en),
-		RD_REGISTER_UNROLL(ch5_pwr_en),
-		RD_REGISTER_UNROLL(ch6_pwr_en),
-		RD_REGISTER_UNROLL(ch7_pwr_en),
+		RD_REGISTER_UNROLL(dw, engine_chgroup),
+		RD_REGISTER_UNROLL(dw, engine_hshake_cnt.lsb),
+		RD_REGISTER_UNROLL(dw, engine_hshake_cnt.msb),
+		RD_REGISTER_UNROLL(dw, ch0_pwr_en),
+		RD_REGISTER_UNROLL(dw, ch1_pwr_en),
+		RD_REGISTER_UNROLL(dw, ch2_pwr_en),
+		RD_REGISTER_UNROLL(dw, ch3_pwr_en),
+		RD_REGISTER_UNROLL(dw, ch4_pwr_en),
+		RD_REGISTER_UNROLL(dw, ch5_pwr_en),
+		RD_REGISTER_UNROLL(dw, ch6_pwr_en),
+		RD_REGISTER_UNROLL(dw, ch7_pwr_en),
 	};
 	struct dentry *regs_dir, *ch_dir;
 	int nr_entries, i;
@@ -238,11 +242,11 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
 	regs_dir = debugfs_create_dir(READ_STR, dir);
 
 	nr_entries = ARRAY_SIZE(debugfs_regs);
-	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
+	dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dir);
 
 	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,
+		dw_edma_debugfs_create_x32(dw, debugfs_unroll_regs, nr_entries,
 					   regs_dir);
 	}
 
@@ -251,15 +255,15 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
 
 		ch_dir = debugfs_create_dir(name, regs_dir);
 
-		dw_edma_debugfs_regs_ch(EDMA_DIR_READ, i, ch_dir);
+		dw_edma_debugfs_regs_ch(dw, EDMA_DIR_READ, i, ch_dir);
 	}
 }
 
-static void dw_edma_debugfs_regs(void)
+static void dw_edma_debugfs_regs(struct dw_edma *dw)
 {
 	const struct dw_edma_debugfs_entry debugfs_regs[] = {
-		REGISTER(ctrl_data_arb_prior),
-		REGISTER(ctrl),
+		REGISTER(dw, ctrl_data_arb_prior),
+		REGISTER(dw, ctrl),
 	};
 	struct dentry *regs_dir;
 	int nr_entries;
@@ -267,23 +271,17 @@ static void dw_edma_debugfs_regs(void)
 	regs_dir = debugfs_create_dir(REGISTERS_STR, dw->debugfs);
 
 	nr_entries = ARRAY_SIZE(debugfs_regs);
-	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
+	dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dir);
 
-	dw_edma_debugfs_regs_wr(regs_dir);
-	dw_edma_debugfs_regs_rd(regs_dir);
+	dw_edma_debugfs_regs_wr(dw, regs_dir);
+	dw_edma_debugfs_regs_rd(dw, regs_dir);
 }
 
 void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
 {
-	if (!debugfs_initialized())
-		return;
-
-	dw = chip->dw;
-	if (!dw)
-		return;
+	struct dw_edma *dw = chip->dw;
 
-	regs = dw->chip->reg_base;
-	if (!regs)
+	if (!debugfs_initialized())
 		return;
 
 	dw->debugfs = debugfs_create_dir(dw->name, NULL);
@@ -292,14 +290,12 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
 	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);
 
-	dw_edma_debugfs_regs();
+	dw_edma_debugfs_regs(dw);
 }
 
 void dw_edma_v0_debugfs_off(struct dw_edma_chip *chip)
 {
-	dw = chip->dw;
-	if (!dw)
-		return;
+	struct dw_edma *dw = chip->dw;
 
 	debugfs_remove_recursive(dw->debugfs);
 	dw->debugfs = NULL;
-- 
2.35.1


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

* [PATCH 18/25] dmaengine: dw-edma: Join Write/Read channels into a single device
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (16 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 17/25] dmaengine: dw-edma: Move eDMA data pointer to DebugFS node descriptor Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-25  7:34   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 19/25] dmaengine: dw-edma: Use DMA-engine device DebugFS subdirectory Serge Semin
                   ` (6 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

Indeed there is no point in such split up because due to multiple reasons.
First of all eDMA read and write channels belong to one physical
controller. Splitting them up illogical. Secondly the channels
differentiating can be done by means of the filtering and the
dma_get_slave_caps() method. Finally having these channels handled
separately not only needlessly complicates the code, but also causes the
DebugFS error printed to console:

>> Debugfs: Directory '1f052000.pcie' with parent 'dmaengine' already present!

So to speak let's join the read/write channels into a single DMA device.
The client drivers will be able to choose the channel with required
capability by getting the DMA slave direction setting. It's default value
is overridden by the dw_edma_device_caps() callback in accordance with the
channel nature.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-core.c | 117 +++++++++++++++--------------
 drivers/dma/dw-edma/dw-edma-core.h |   5 +-
 2 files changed, 62 insertions(+), 60 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index cefa73412bf7..a391e44da039 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -209,6 +209,24 @@ static void dw_edma_start_transfer(struct dw_edma_chan *chan)
 	desc->chunks_alloc--;
 }
 
+static void dw_edma_device_caps(struct dma_chan *dchan,
+				struct dma_slave_caps *caps)
+{
+	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+
+	if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
+		if (chan->dir == EDMA_DIR_READ)
+			caps->directions = BIT(DMA_DEV_TO_MEM);
+		else
+			caps->directions = BIT(DMA_MEM_TO_DEV);
+	} else {
+		if (chan->dir == EDMA_DIR_WRITE)
+			caps->directions = BIT(DMA_DEV_TO_MEM);
+		else
+			caps->directions = BIT(DMA_MEM_TO_DEV);
+	}
+}
+
 static int dw_edma_device_config(struct dma_chan *dchan,
 				 struct dma_slave_config *config)
 {
@@ -723,8 +741,8 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
 	pm_runtime_put(chan->dw->chip->dev);
 }
 
-static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
-				 u32 wr_alloc, u32 rd_alloc)
+static int dw_edma_channel_setup(struct dw_edma_chip *chip, u32 wr_alloc,
+				 u32 rd_alloc)
 {
 	struct dw_edma_region *dt_region;
 	struct device *dev = chip->dev;
@@ -732,27 +750,15 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
 	struct dw_edma_chan *chan;
 	struct dw_edma_irq *irq;
 	struct dma_device *dma;
-	u32 alloc, off_alloc;
-	u32 i, j, cnt;
-	int err = 0;
+	u32 i, ch_cnt;
 	u32 pos;
 
-	if (write) {
-		i = 0;
-		cnt = dw->wr_ch_cnt;
-		dma = &dw->wr_edma;
-		alloc = wr_alloc;
-		off_alloc = 0;
-	} else {
-		i = dw->wr_ch_cnt;
-		cnt = dw->rd_ch_cnt;
-		dma = &dw->rd_edma;
-		alloc = rd_alloc;
-		off_alloc = wr_alloc;
-	}
+	ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
+	dma = &dw->dma;
 
 	INIT_LIST_HEAD(&dma->channels);
-	for (j = 0; (alloc || chip->nr_irqs == 1) && j < cnt; j++, i++) {
+
+	for (i = 0; i < ch_cnt; i++) {
 		chan = &dw->chan[i];
 
 		dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
@@ -762,52 +768,62 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
 		chan->vc.chan.private = dt_region;
 
 		chan->dw = dw;
-		chan->id = j;
-		chan->dir = write ? EDMA_DIR_WRITE : EDMA_DIR_READ;
+
+		if (i < dw->wr_ch_cnt) {
+			chan->id = i;
+			chan->dir = EDMA_DIR_WRITE;
+		} else {
+			chan->id = i - dw->wr_ch_cnt;
+			chan->dir = EDMA_DIR_READ;
+		}
+
 		chan->configured = false;
 		chan->request = EDMA_REQ_NONE;
 		chan->status = EDMA_ST_IDLE;
 
-		if (write)
-			chan->ll_max = (chip->ll_region_wr[j].sz / EDMA_LL_SZ);
+		if (chan->dir == EDMA_DIR_WRITE)
+			chan->ll_max = (chip->ll_region_wr[chan->id].sz / EDMA_LL_SZ);
 		else
-			chan->ll_max = (chip->ll_region_rd[j].sz / EDMA_LL_SZ);
+			chan->ll_max = (chip->ll_region_rd[chan->id].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);
+			 chan->dir == EDMA_DIR_WRITE ? "write" : "read",
+			 chan->id, chan->ll_max);
 
 		if (chip->nr_irqs == 1)
 			pos = 0;
+		else if (chan->dir == EDMA_DIR_WRITE)
+			pos = chan->id % wr_alloc;
 		else
-			pos = off_alloc + (j % alloc);
+			pos = wr_alloc + chan->id % rd_alloc;
 
 		irq = &dw->irq[pos];
 
-		if (write)
-			irq->wr_mask |= BIT(j);
+		if (chan->dir == EDMA_DIR_WRITE)
+			irq->wr_mask |= BIT(chan->id);
 		else
-			irq->rd_mask |= BIT(j);
+			irq->rd_mask |= BIT(chan->id);
 
 		irq->dw = dw;
 		memcpy(&chan->msi, &irq->msi, sizeof(chan->msi));
 
 		dev_vdbg(dev, "MSI:\t\tChannel %s[%u] addr=0x%.8x%.8x, data=0x%.8x\n",
-			 write ? "write" : "read", j,
+			 chan->dir == EDMA_DIR_WRITE  ? "write" : "read", chan->id,
 			 chan->msi.address_hi, chan->msi.address_lo,
 			 chan->msi.data);
 
 		chan->vc.desc_free = vchan_free_desc;
 		vchan_init(&chan->vc, dma);
 
-		if (write) {
-			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;
+		if (chan->dir == EDMA_DIR_WRITE) {
+			dt_region->paddr = chip->dt_region_wr[chan->id].paddr;
+			dt_region->vaddr = chip->dt_region_wr[chan->id].vaddr;
+			dt_region->sz = chip->dt_region_wr[chan->id].sz;
 		} else {
-			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;
+			dt_region->paddr = chip->dt_region_rd[chan->id].paddr;
+			dt_region->vaddr = chip->dt_region_rd[chan->id].vaddr;
+			dt_region->sz = chip->dt_region_rd[chan->id].sz;
 		}
 
 		dw_edma_v0_core_device_config(chan);
@@ -819,7 +835,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
 	dma_cap_set(DMA_CYCLIC, dma->cap_mask);
 	dma_cap_set(DMA_PRIVATE, dma->cap_mask);
 	dma_cap_set(DMA_INTERLEAVE, dma->cap_mask);
-	dma->directions = BIT(write ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV);
+	dma->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
 	dma->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
 	dma->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
 	dma->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
@@ -828,6 +844,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
 	dma->dev = chip->dev;
 	dma->device_alloc_chan_resources = dw_edma_alloc_chan_resources;
 	dma->device_free_chan_resources = dw_edma_free_chan_resources;
+	dma->device_caps = dw_edma_device_caps;
 	dma->device_config = dw_edma_device_config;
 	dma->device_pause = dw_edma_device_pause;
 	dma->device_resume = dw_edma_device_resume;
@@ -841,9 +858,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
 	dma_set_max_seg_size(dma->dev, U32_MAX);
 
 	/* Register DMA device */
-	err = dma_async_device_register(dma);
-
-	return err;
+	return dma_async_device_register(dma);
 }
 
 static inline void dw_edma_dec_irq_alloc(int *nr_irqs, u32 *alloc, u16 cnt)
@@ -982,13 +997,8 @@ int dw_edma_probe(struct dw_edma_chip *chip)
 	if (err)
 		return err;
 
-	/* Setup write channels */
-	err = dw_edma_channel_setup(chip, true, wr_alloc, rd_alloc);
-	if (err)
-		goto err_irq_free;
-
-	/* Setup read channels */
-	err = dw_edma_channel_setup(chip, false, wr_alloc, rd_alloc);
+	/* Setup write/read channels */
+	err = dw_edma_channel_setup(chip, wr_alloc, rd_alloc);
 	if (err)
 		goto err_irq_free;
 
@@ -1028,15 +1038,8 @@ int dw_edma_remove(struct dw_edma_chip *chip)
 	pm_runtime_disable(dev);
 
 	/* Deregister eDMA device */
-	dma_async_device_unregister(&dw->wr_edma);
-	list_for_each_entry_safe(chan, _chan, &dw->wr_edma.channels,
-				 vc.chan.device_node) {
-		tasklet_kill(&chan->vc.task);
-		list_del(&chan->vc.chan.device_node);
-	}
-
-	dma_async_device_unregister(&dw->rd_edma);
-	list_for_each_entry_safe(chan, _chan, &dw->rd_edma.channels,
+	dma_async_device_unregister(&dw->dma);
+	list_for_each_entry_safe(chan, _chan, &dw->dma.channels,
 				 vc.chan.device_node) {
 		tasklet_kill(&chan->vc.task);
 		list_del(&chan->vc.chan.device_node);
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index e254c2fc3d9c..ec9f84a857d1 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -98,10 +98,9 @@ struct dw_edma_irq {
 struct dw_edma {
 	char				name[20];
 
-	struct dma_device		wr_edma;
-	u16				wr_ch_cnt;
+	struct dma_device		dma;
 
-	struct dma_device		rd_edma;
+	u16				wr_ch_cnt;
 	u16				rd_ch_cnt;
 
 	struct dw_edma_irq		*irq;
-- 
2.35.1


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

* [PATCH 19/25] dmaengine: dw-edma: Use DMA-engine device DebugFS subdirectory
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (17 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 18/25] dmaengine: dw-edma: Join Write/Read channels into a single device Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-25  7:41   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 20/25] dmaengine: dw-edma: Use non-atomic io-64 methods Serge Semin
                   ` (5 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

Since all DW eDMA read and write channels are now installed in a framework
of a single DMA-engine device, we can freely move all the DW eDMA-specific
DebugFS nodes into a ready-to-use DMA-engine DebugFS subdirectory. It's
created during the DMA-device registration and can be found in the
dma_device.dbg_dev_root field.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-core.c       |  3 ---
 drivers/dma/dw-edma/dw-edma-core.h       |  3 ---
 drivers/dma/dw-edma/dw-edma-v0-core.c    |  5 -----
 drivers/dma/dw-edma/dw-edma-v0-core.h    |  1 -
 drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 18 ++++--------------
 drivers/dma/dw-edma/dw-edma-v0-debugfs.h |  5 -----
 6 files changed, 4 insertions(+), 31 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index a391e44da039..bc530f0a2468 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -1045,9 +1045,6 @@ int dw_edma_remove(struct dw_edma_chip *chip)
 		list_del(&chan->vc.chan.device_node);
 	}
 
-	/* Turn debugfs off */
-	dw_edma_v0_core_debugfs_off(chip);
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(dw_edma_remove);
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index ec9f84a857d1..980adb079182 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -110,9 +110,6 @@ struct dw_edma {
 	raw_spinlock_t			lock;		/* Only for legacy */
 
 	struct dw_edma_chip             *chip;
-#ifdef CONFIG_DEBUG_FS
-	struct dentry			*debugfs;
-#endif /* CONFIG_DEBUG_FS */
 };
 
 struct dw_edma_sg {
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index 013d9a9cb991..6b303d5a6b2a 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -511,8 +511,3 @@ void dw_edma_v0_core_debugfs_on(struct dw_edma_chip *chip)
 {
 	dw_edma_v0_debugfs_on(chip);
 }
-
-void dw_edma_v0_core_debugfs_off(struct dw_edma_chip *chip)
-{
-	dw_edma_v0_debugfs_off(chip);
-}
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.h b/drivers/dma/dw-edma/dw-edma-v0-core.h
index 2afa626b8300..43e01844375a 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.h
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.h
@@ -23,6 +23,5 @@ 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);
 /* eDMA debug fs callbacks */
 void dw_edma_v0_core_debugfs_on(struct dw_edma_chip *chip);
-void dw_edma_v0_core_debugfs_off(struct dw_edma_chip *chip);
 
 #endif /* _DW_EDMA_V0_CORE_H */
diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
index 353269a3680b..319a3c790dc4 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
@@ -268,7 +268,7 @@ static void dw_edma_debugfs_regs(struct dw_edma *dw)
 	struct dentry *regs_dir;
 	int nr_entries;
 
-	regs_dir = debugfs_create_dir(REGISTERS_STR, dw->debugfs);
+	regs_dir = debugfs_create_dir(REGISTERS_STR, dw->dma.dbg_dev_root);
 
 	nr_entries = ARRAY_SIZE(debugfs_regs);
 	dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dir);
@@ -284,19 +284,9 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
 	if (!debugfs_initialized())
 		return;
 
-	dw->debugfs = debugfs_create_dir(dw->name, NULL);
-
-	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);
+	debugfs_create_u32("mf", 0444, dw->dma.dbg_dev_root, &dw->chip->mf);
+	debugfs_create_u16("wr_ch_cnt", 0444, dw->dma.dbg_dev_root, &dw->wr_ch_cnt);
+	debugfs_create_u16("rd_ch_cnt", 0444, dw->dma.dbg_dev_root, &dw->rd_ch_cnt);
 
 	dw_edma_debugfs_regs(dw);
 }
-
-void dw_edma_v0_debugfs_off(struct dw_edma_chip *chip)
-{
-	struct dw_edma *dw = chip->dw;
-
-	debugfs_remove_recursive(dw->debugfs);
-	dw->debugfs = NULL;
-}
diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.h b/drivers/dma/dw-edma/dw-edma-v0-debugfs.h
index d0ff25a9ea5c..eb11802c2b76 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.h
+++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.h
@@ -13,15 +13,10 @@
 
 #ifdef CONFIG_DEBUG_FS
 void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip);
-void dw_edma_v0_debugfs_off(struct dw_edma_chip *chip);
 #else
 static inline void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
 {
 }
-
-static inline void dw_edma_v0_debugfs_off(struct dw_edma_chip *chip)
-{
-}
 #endif /* CONFIG_DEBUG_FS */
 
 #endif /* _DW_EDMA_V0_DEBUG_FS_H */
-- 
2.35.1


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

* [PATCH 20/25] dmaengine: dw-edma: Use non-atomic io-64 methods
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (18 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 19/25] dmaengine: dw-edma: Use DMA-engine device DebugFS subdirectory Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-25  8:28   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 21/25] dmaengine: dw-edma: Drop DT-region allocation Serge Semin
                   ` (4 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

Instead of splitting the 64-bits IOs up into two 32-bits ones it's
possible to use an available set of the non-atomic readq/writeq methods
implemented exactly for such cases. They are defined in the dedicated
header files io-64-nonatomic-lo-hi.h/io-64-nonatomic-hi-lo.h. So in case
if the 64-bits readq/writeq methods are unavailable on some platforms at
consideration, the corresponding drivers can have any of these headers
included and stop locally re-implementing the 64-bits IO accessors taking
into account the non-atomic nature of the included methods. Let's do that
in the DW eDMA driver too. Note by doing so we can discard the
CONFIG_64BIT config ifdefs from the code. Also note that if a platform
doesn't support 64-bit DBI IOs then the corresponding accessors will just
directly call the lo_hi_readq()/lo_hi_writeq() methods.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-v0-core.c | 71 +++++++++------------------
 1 file changed, 24 insertions(+), 47 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index 6b303d5a6b2a..ebb860e19c75 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -8,6 +8,8 @@
 
 #include <linux/bitfield.h>
 
+#include <linux/io-64-nonatomic-lo-hi.h>
+
 #include "dw-edma-core.h"
 #include "dw-edma-v0-core.h"
 #include "dw-edma-v0-regs.h"
@@ -53,8 +55,6 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
 		SET_32(dw, rd_##name, value);		\
 	} while (0)
 
-#ifdef CONFIG_64BIT
-
 #define SET_64(dw, name, value)				\
 	writeq(value, &(__dw_regs(dw)->name))
 
@@ -80,8 +80,6 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
 		SET_64(dw, rd_##name, value);		\
 	} while (0)
 
-#endif /* CONFIG_64BIT */
-
 #define SET_COMPAT(dw, name, value)			\
 	writel(value, &(__dw_regs(dw)->type.unroll.name))
 
@@ -164,14 +162,13 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
 #define SET_LL_32(ll, value) \
 	writel(value, ll)
 
-#ifdef CONFIG_64BIT
-
 static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
 			     u64 value, void __iomem *addr)
 {
+	unsigned long flags;
+
 	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
 		u32 viewport_sel;
-		unsigned long flags;
 
 		raw_spin_lock_irqsave(&dw->lock, flags);
 
@@ -181,22 +178,25 @@ static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
 
 		writel(viewport_sel,
 		       &(__dw_regs(dw)->type.legacy.viewport_sel));
+	}
+
+	if (dw->chip->flags & DW_EDMA_CHIP_32BIT_DBI)
+		lo_hi_writeq(value, addr);
+	else
 		writeq(value, addr);
 
+	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY)
 		raw_spin_unlock_irqrestore(&dw->lock, flags);
-	} else {
-		writeq(value, addr);
-	}
 }
 
 static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
 			   const void __iomem *addr)
 {
-	u32 value;
+	unsigned long flags;
+	u64 value;
 
 	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
 		u32 viewport_sel;
-		unsigned long flags;
 
 		raw_spin_lock_irqsave(&dw->lock, flags);
 
@@ -206,12 +206,15 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
 
 		writel(viewport_sel,
 		       &(__dw_regs(dw)->type.legacy.viewport_sel));
+	}
+
+	if (dw->chip->flags & DW_EDMA_CHIP_32BIT_DBI)
+		value = lo_hi_readq(addr);
+	else
 		value = readq(addr);
 
+	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY)
 		raw_spin_unlock_irqrestore(&dw->lock, flags);
-	} else {
-		value = readq(addr);
-	}
 
 	return value;
 }
@@ -225,8 +228,6 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
 #define SET_LL_64(ll, value) \
 	writeq(value, ll)
 
-#endif /* CONFIG_64BIT */
-
 /* eDMA management callbacks */
 void dw_edma_v0_core_off(struct dw_edma *dw)
 {
@@ -325,19 +326,10 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
 		/* Transfer size */
 		SET_LL_32(&lli[i].transfer_size, child->sz);
 		/* SAR */
-		#ifdef CONFIG_64BIT
-			SET_LL_64(&lli[i].sar.reg, child->sar);
-		#else /* CONFIG_64BIT */
-			SET_LL_32(&lli[i].sar.lsb, lower_32_bits(child->sar));
-			SET_LL_32(&lli[i].sar.msb, upper_32_bits(child->sar));
-		#endif /* CONFIG_64BIT */
+		SET_LL_64(&lli[i].sar.reg, child->sar);
 		/* DAR */
-		#ifdef CONFIG_64BIT
-			SET_LL_64(&lli[i].dar.reg, child->dar);
-		#else /* CONFIG_64BIT */
-			SET_LL_32(&lli[i].dar.lsb, lower_32_bits(child->dar));
-			SET_LL_32(&lli[i].dar.msb, upper_32_bits(child->dar));
-		#endif /* CONFIG_64BIT */
+		SET_LL_64(&lli[i].dar.reg, child->dar);
+
 		i++;
 	}
 
@@ -349,12 +341,7 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
 	/* Channel control */
 	SET_LL_32(&llp->control, control);
 	/* Linked list */
-	#ifdef CONFIG_64BIT
-		SET_LL_64(&llp->llp.reg, chunk->ll_region.paddr);
-	#else /* CONFIG_64BIT */
-		SET_LL_32(&llp->llp.lsb, lower_32_bits(chunk->ll_region.paddr));
-		SET_LL_32(&llp->llp.msb, upper_32_bits(chunk->ll_region.paddr));
-	#endif /* CONFIG_64BIT */
+	SET_LL_64(&llp->llp.reg, chunk->ll_region.paddr);
 }
 
 void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
@@ -417,18 +404,8 @@ 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 */
-		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));
-		} else {
-		#ifdef CONFIG_64BIT
-			SET_CH_64(dw, chan->dir, chan->id, llp.reg,
-				  chunk->ll_region.paddr);
-		#endif
-		}
+		SET_CH_64(dw, chan->dir, chan->id, llp.reg,
+			  chunk->ll_region.paddr);
 	}
 	/* Doorbell */
 	SET_RW_32(dw, chan->dir, doorbell,
-- 
2.35.1


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

* [PATCH 21/25] dmaengine: dw-edma: Drop DT-region allocation
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (19 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 20/25] dmaengine: dw-edma: Use non-atomic io-64 methods Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-25  8:33   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 22/25] dmaengine: dw-edma: Replace chip ID number with device name Serge Semin
                   ` (3 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

There is no point in allocating an additional memory for the data target
regions passed then to the client drivers. Just use the already available
structures defined in the dw_edma_chip instance.

Note these regions are unused in normal circumstances since they are
specific to the case of eDMA being embedded into the DW PCIe End-point and
having it's CSRs accessible over a End-point' BAR. This case is only known
to be implemented as a part of the Synopsys PCIe EndPoint IP prototype
kit.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-core.c | 21 ++++-----------------
 1 file changed, 4 insertions(+), 17 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index bc530f0a2468..dbe1119fd1d2 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -744,7 +744,6 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
 static int dw_edma_channel_setup(struct dw_edma_chip *chip, u32 wr_alloc,
 				 u32 rd_alloc)
 {
-	struct dw_edma_region *dt_region;
 	struct device *dev = chip->dev;
 	struct dw_edma *dw = chip->dw;
 	struct dw_edma_chan *chan;
@@ -761,12 +760,6 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, u32 wr_alloc,
 	for (i = 0; i < ch_cnt; i++) {
 		chan = &dw->chan[i];
 
-		dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
-		if (!dt_region)
-			return -ENOMEM;
-
-		chan->vc.chan.private = dt_region;
-
 		chan->dw = dw;
 
 		if (i < dw->wr_ch_cnt) {
@@ -814,17 +807,11 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, u32 wr_alloc,
 			 chan->msi.data);
 
 		chan->vc.desc_free = vchan_free_desc;
-		vchan_init(&chan->vc, dma);
+		chan->vc.chan.private = chan->dir == EDMA_DIR_WRITE ?
+					&dw->chip->dt_region_wr[chan->id] :
+					&dw->chip->dt_region_rd[chan->id];
 
-		if (chan->dir == EDMA_DIR_WRITE) {
-			dt_region->paddr = chip->dt_region_wr[chan->id].paddr;
-			dt_region->vaddr = chip->dt_region_wr[chan->id].vaddr;
-			dt_region->sz = chip->dt_region_wr[chan->id].sz;
-		} else {
-			dt_region->paddr = chip->dt_region_rd[chan->id].paddr;
-			dt_region->vaddr = chip->dt_region_rd[chan->id].vaddr;
-			dt_region->sz = chip->dt_region_rd[chan->id].sz;
-		}
+		vchan_init(&chan->vc, dma);
 
 		dw_edma_v0_core_device_config(chan);
 	}
-- 
2.35.1


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

* [PATCH 22/25] dmaengine: dw-edma: Replace chip ID number with device name
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (20 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 21/25] dmaengine: dw-edma: Drop DT-region allocation Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-25 10:02   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 23/25] dmaengine: dw-edma: Bypass dma-ranges mapping for the local setup Serge Semin
                   ` (2 subsequent siblings)
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

Using some abstract number as the DW eDMA chip identifier isn't really
practical. First of all there can be more than one DW eDMA controller on
the platform some of them can be detected as the PCIe end-points, some of
them can be embedded into the DW PCIe Root Port/End-point controllers.
Seeing some abstract number in for instance IRQ handlers list doesn't give
a notion regarding their reference to the particular DMA controller.
Secondly current DW eDMA chip id implementation doesn't provide the
multi-eDMA platforms support for same reason of possibly having eDMA
detected on different system buses. At the same time re-implementing
something ida-based won't give much benefits especially seeing the DW eDMA
chip ID is only used in the IRQ request procedure. So to speak in order to
preserve the code simplicity and get to have the multi-eDMA platforms
support let's just use the parental device name to create the DW eDMA
controller name.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-core.c | 3 ++-
 drivers/dma/dw-edma/dw-edma-core.h | 2 +-
 drivers/dma/dw-edma/dw-edma-pcie.c | 1 -
 include/linux/dma/edma.h           | 1 -
 4 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index dbe1119fd1d2..72a51970bfba 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -970,7 +970,8 @@ int dw_edma_probe(struct dw_edma_chip *chip)
 	if (!dw->chan)
 		return -ENOMEM;
 
-	snprintf(dw->name, sizeof(dw->name), "dw-edma-core:%d", chip->id);
+	snprintf(dw->name, sizeof(dw->name), "dw-edma-core:%s",
+		 dev_name(chip->dev));
 
 	/* Disable eDMA, only to establish the ideal initial conditions */
 	dw_edma_v0_core_off(dw);
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index 980adb079182..dc25798d4ba9 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -96,7 +96,7 @@ struct dw_edma_irq {
 };
 
 struct dw_edma {
-	char				name[20];
+	char				name[30];
 
 	struct dma_device		dma;
 
diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index f530bacfd716..3f9dadc73854 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -222,7 +222,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 
 	/* Data structure initialization */
 	chip->dev = dev;
-	chip->id = pdev->devfn;
 
 	chip->mf = vsec_data.mf;
 	chip->nr_irqs = nr_irqs;
diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
index 5cc87cfdd685..241c5a97ddf4 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -73,7 +73,6 @@ enum dw_edma_map_format {
  */
 struct dw_edma_chip {
 	struct device		*dev;
-	int			id;
 	int			nr_irqs;
 	const struct dw_edma_core_ops   *ops;
 	u32			flags;
-- 
2.35.1


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

* [PATCH 23/25] dmaengine: dw-edma: Bypass dma-ranges mapping for the local setup
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (21 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 22/25] dmaengine: dw-edma: Replace chip ID number with device name Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-25 18:10   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 24/25] dmaengine: dw-edma: Skip cleanup procedure if no private data found Serge Semin
  2022-03-24  1:48 ` [PATCH 25/25] PCI: dwc: Add DW eDMA engine support Serge Semin
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

DW eDMA doesn't perform any translation of the traffic generated on the
CPU/Application side. It just generates read/write AXI-bus requests with
the specified addresses. But in case if the dma-ranges DT-property is
specified for a platform device node, Linux will use it to map the CPU
memory regions into the DMAable bus ranges. This isn't what we want for
the eDMA embedded into the locally accessed DW PCIe Root Port and
End-point. In order to work that around let's set the chan_dma_dev flag
for each DW eDMA channel thus forcing the client drivers to getting a
custom dma-ranges-less parental device for the mappings.

Note it will only work for the client drivers using the
dmaengine_get_dma_device() method to get the parental DMA device.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-core.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 72a51970bfba..ca5cd7c99571 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -716,6 +716,21 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
 	if (chan->status != EDMA_ST_IDLE)
 		return -EBUSY;
 
+	/* Bypass the dma-ranges based memory regions mapping since the
+	 * inbound iATU only affects the traffic incoming from the
+	 * PCIe bus.
+	 */
+	if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
+		dchan->dev->chan_dma_dev = true;
+
+		dchan->dev->device.dma_coherent = chan->dw->chip->dev->dma_coherent;
+		dma_coerce_mask_and_coherent(&dchan->dev->device,
+					     dma_get_mask(chan->dw->chip->dev));
+		dchan->dev->device.dma_parms = chan->dw->chip->dev->dma_parms;
+	} else {
+		dchan->dev->chan_dma_dev = false;
+	}
+
 	pm_runtime_get(chan->dw->chip->dev);
 
 	return 0;
-- 
2.35.1


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

* [PATCH 24/25] dmaengine: dw-edma: Skip cleanup procedure if no private data found
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (22 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 23/25] dmaengine: dw-edma: Bypass dma-ranges mapping for the local setup Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-25 18:15   ` Manivannan Sadhasivam
  2022-03-24  1:48 ` [PATCH 25/25] PCI: dwc: Add DW eDMA engine support Serge Semin
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

DW eDMA driver private data is preserved in the passed DW eDMA chip info
structure. If either probe procedure failed or for some reason the passed
info object doesn't have private data pointer initialized we need to halt
the DMA device cleanup procedure in order to prevent possible system
crashes.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/dma/dw-edma/dw-edma-core.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index ca5cd7c99571..b932682a8ba8 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -1030,6 +1030,10 @@ int dw_edma_remove(struct dw_edma_chip *chip)
 	struct dw_edma *dw = chip->dw;
 	int i;
 
+	/* Skip removal if no private data found */
+	if (!dw)
+		return -ENODEV;
+
 	/* Disable eDMA */
 	dw_edma_v0_core_off(dw);
 
-- 
2.35.1


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

* [PATCH 25/25] PCI: dwc: Add DW eDMA engine support
  2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
                   ` (23 preceding siblings ...)
  2022-03-24  1:48 ` [PATCH 24/25] dmaengine: dw-edma: Skip cleanup procedure if no private data found Serge Semin
@ 2022-03-24  1:48 ` Serge Semin
  2022-03-28 14:15   ` Manivannan Sadhasivam
  24 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-24  1:48 UTC (permalink / raw)
  To: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Manivannan Sadhasivam, Lorenzo Pieralisi, Rob Herring,
	Krzysztof Wilczyński
  Cc: Serge Semin, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	linux-pci, dmaengine, linux-kernel

Since the DW eDMA driver now supports eDMA controllers embedded into the
locally accessible DW PCIe Root Ports and End-points, we can use the
updated interface to register DW eDMA as DMA engine device if it's
available. In order to successfully do that the DW PCIe core driver need
to perform some preparations first. First of all it needs to find out the
eDMA controller CSRs base address, whether they are accessible over the
Port Logic or iATU unrolled space. Afterwards it can try to auto-detect
the eDMA controller availability and number of it's read/write channels.
If none was found the procedure will just silently halt with no error
returned. Secondly the platform is supposed to provide either combined or
per-channel IRQ signals. If no valid IRQs set is found the procedure will
also halt with no error returned so to be backward compatible with
platforms where DW PCIe controllers have eDMA embedded but lack of the
IRQs defined for them. Finally before actually probing the eDMA device we
need to allocate LLP items buffers. After that the DW eDMA can be
registered. If registration is successful the info-message regarding the
number of detected Read/Write eDMA channels will be printed to the system
log in the same way as it's done for iATU settings.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 .../pci/controller/dwc/pcie-designware-ep.c   |   4 +
 .../pci/controller/dwc/pcie-designware-host.c |  13 +-
 drivers/pci/controller/dwc/pcie-designware.c  | 188 ++++++++++++++++++
 drivers/pci/controller/dwc/pcie-designware.h  |  23 ++-
 4 files changed, 225 insertions(+), 3 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 23401f17e8f0..b2840d1a5b9a 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -712,6 +712,10 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
 
 	dw_pcie_iatu_detect(pci);
 
+	ret = dw_pcie_edma_detect(pci);
+	if (ret)
+		return ret;
+
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
 	if (!res)
 		return -EINVAL;
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 715a13b90e43..048b452ee4f3 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -405,14 +405,18 @@ int dw_pcie_host_init(struct pcie_port *pp)
 
 	dw_pcie_iatu_detect(pci);
 
-	ret = dw_pcie_setup_rc(pp);
+	ret = dw_pcie_edma_detect(pci);
 	if (ret)
 		goto err_free_msi;
 
+	ret = dw_pcie_setup_rc(pp);
+	if (ret)
+		goto err_edma_remove;
+
 	if (!dw_pcie_link_up(pci) && pci->ops && pci->ops->start_link) {
 		ret = pci->ops->start_link(pci);
 		if (ret)
-			goto err_free_msi;
+			goto err_edma_remove;
 	}
 
 	/* Ignore errors, the link may come up later */
@@ -430,6 +434,9 @@ int dw_pcie_host_init(struct pcie_port *pp)
 	if (pci->ops && pci->ops->stop_link)
 		pci->ops->stop_link(pci);
 
+err_edma_remove:
+	dw_pcie_edma_remove(pci);
+
 err_free_msi:
 	if (pp->has_msi_ctrl)
 		dw_pcie_free_msi(pp);
@@ -452,6 +459,8 @@ void dw_pcie_host_deinit(struct pcie_port *pp)
 	if (pci->ops && pci->ops->stop_link)
 		pci->ops->stop_link(pci);
 
+	dw_pcie_edma_remove(pci);
+
 	if (pp->has_msi_ctrl)
 		dw_pcie_free_msi(pp);
 
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 4a95a7b112e9..dbe39a7ecb71 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -11,6 +11,7 @@
 #include <linux/align.h>
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/dma/edma.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include <linux/sizes.h>
@@ -680,6 +681,193 @@ void dw_pcie_iatu_detect(struct dw_pcie *pci)
 		 pci->region_align / SZ_1K, (pci->region_limit + 1) / SZ_1G);
 }
 
+static u32 dw_pcie_readl_dma(struct dw_pcie *pci, u32 reg)
+{
+	u32 val = 0;
+	int ret;
+
+	if (pci->ops && pci->ops->read_dbi)
+		return pci->ops->read_dbi(pci, pci->edma.reg_base, reg, 4);
+
+	ret = dw_pcie_read(pci->edma.reg_base + reg, 4, &val);
+	if (ret)
+		dev_err(pci->dev, "Read DMA address failed\n");
+
+	return val;
+}
+
+static bool dw_pcie_edma_unroll_enabled(struct dw_pcie *pci)
+{
+	u32 val;
+
+	val = dw_pcie_readl_dbi(pci, PCIE_DMA_VIEWPORT_BASE + PCIE_DMA_CTRL);
+	if (val == 0xffffffff)
+		return true;
+
+	return false;
+}
+
+static int dw_pcie_edma_irq_vector(struct device *dev, unsigned int nr)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	char name[6];
+	int ret;
+
+	if (nr >= EDMA_MAX_WR_CH + EDMA_MAX_RD_CH)
+		return -EINVAL;
+
+	ret = platform_get_irq_byname_optional(pdev, "dma");
+	if (ret > 0)
+		return ret;
+
+	snprintf(name, sizeof(name), "dma%u", nr);
+
+	return platform_get_irq_byname_optional(pdev, name);
+}
+
+static struct dw_edma_core_ops dw_pcie_edma_ops = {
+	.irq_vector = dw_pcie_edma_irq_vector,
+};
+
+static int dw_pcie_edma_detect_channels(struct dw_pcie *pci)
+{
+	u32 val;
+
+	val = dw_pcie_readl_dma(pci, PCIE_DMA_CTRL);
+	if (!val || val == 0xffffffff)
+		return 0;
+
+	pci->edma.ll_wr_cnt = FIELD_GET(PCIE_DMA_NUM_WR_CHAN, val);
+	pci->edma.ll_rd_cnt = FIELD_GET(PCIE_DMA_NUM_RD_CHAN, val);
+
+	if (pci->edma.ll_wr_cnt > EDMA_MAX_WR_CH ||
+	    pci->edma.ll_rd_cnt > EDMA_MAX_RD_CH)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int dw_pcie_edma_irq_verify(struct dw_pcie *pci)
+{
+	struct platform_device *pdev = to_platform_device(pci->dev);
+	u16 ch_cnt = pci->edma.ll_wr_cnt + pci->edma.ll_rd_cnt;
+	char name[6];
+	int ret;
+
+	if (pci->edma.nr_irqs == 1)
+		return 0;
+	else if (pci->edma.nr_irqs > 1)
+		return pci->edma.nr_irqs != ch_cnt ? -EINVAL : 0;
+
+	ret = platform_get_irq_byname_optional(pdev, "dma");
+	if (ret > 0) {
+		pci->edma.nr_irqs = 1;
+		return 0;
+	}
+
+	for (; pci->edma.nr_irqs < ch_cnt; pci->edma.nr_irqs++) {
+		snprintf(name, sizeof(name), "dma%d", pci->edma.nr_irqs);
+
+		ret = platform_get_irq_byname_optional(pdev, name);
+		if (ret <= 0)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int dw_pcie_edma_ll_alloc(struct dw_pcie *pci)
+{
+	struct dw_edma_region *ll;
+	dma_addr_t paddr;
+	int i;
+
+	for (i = 0; i < pci->edma.ll_wr_cnt; i++) {
+		ll = &pci->edma.ll_region_wr[i];
+		ll->sz = DMA_LLP_MEM_SIZE;
+		ll->vaddr = dmam_alloc_coherent(pci->dev, ll->sz,
+						&paddr, GFP_KERNEL);
+		if (!ll->vaddr)
+			return -ENOMEM;
+
+		ll->paddr = paddr;
+	}
+
+	for (i = 0; i < pci->edma.ll_rd_cnt; i++) {
+		ll = &pci->edma.ll_region_rd[i];
+		ll->sz = DMA_LLP_MEM_SIZE;
+		ll->vaddr = dmam_alloc_coherent(pci->dev, ll->sz,
+						&paddr, GFP_KERNEL);
+		if (!ll->vaddr)
+			return -ENOMEM;
+
+		ll->paddr = paddr;
+	}
+
+	return 0;
+}
+
+int dw_pcie_edma_detect(struct dw_pcie *pci)
+{
+	int ret;
+
+	pci->edma.dev = pci->dev;
+	if (!pci->edma.ops)
+		pci->edma.ops = &dw_pcie_edma_ops;
+	pci->edma.flags |= DW_EDMA_CHIP_LOCAL;
+
+	pci->edma_unroll_enabled = dw_pcie_edma_unroll_enabled(pci);
+	if (pci->edma_unroll_enabled && pci->iatu_unroll_enabled) {
+		pci->edma.mf = EDMA_MF_EDMA_UNROLL;
+		if (pci->atu_base != pci->dbi_base + DEFAULT_DBI_ATU_OFFSET)
+			pci->edma.reg_base = pci->atu_base + PCIE_DMA_UNROLL_BASE;
+		else
+			pci->edma.reg_base = pci->dbi_base + DEFAULT_DBI_DMA_OFFSET;
+	} else {
+		pci->edma.mf = EDMA_MF_EDMA_LEGACY;
+		pci->edma.reg_base = pci->dbi_base + PCIE_DMA_VIEWPORT_BASE;
+	}
+
+	ret = dw_pcie_edma_detect_channels(pci);
+	if (ret) {
+		dev_err(pci->dev, "Unexpected NoF eDMA channels found\n");
+		return ret;
+	}
+
+	/* Skip any further initialization if no eDMA found */
+	if (!pci->edma.ll_wr_cnt && !pci->edma.ll_rd_cnt)
+		return 0;
+
+	/* Don't return failure here for the backward compatibility */
+	ret = dw_pcie_edma_irq_verify(pci);
+	if (ret) {
+		dev_err(pci->dev, "No valid eDMA IRQs set found\n");
+		return 0;
+	}
+
+	ret = dw_pcie_edma_ll_alloc(pci);
+	if (ret) {
+		dev_err(pci->dev, "Couldn't allocate LLP memory\n");
+		return ret;
+	}
+
+	ret = dw_edma_probe(&pci->edma);
+	if (ret) {
+		dev_err(pci->dev, "Couldn't register eDMA device\n");
+		return ret;
+	}
+
+	dev_info(pci->dev, "eDMA channels: %hu wr, %hu rd\n",
+		 pci->edma.ll_wr_cnt, pci->edma.ll_rd_cnt);
+
+	return 0;
+}
+
+void dw_pcie_edma_remove(struct dw_pcie *pci)
+{
+	dw_edma_remove(&pci->edma);
+}
+
 void dw_pcie_setup(struct dw_pcie *pci)
 {
 	u32 val;
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 11c52d2eaf79..9b92f79664f2 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -13,6 +13,7 @@
 
 #include <linux/bitfield.h>
 #include <linux/dma-mapping.h>
+#include <linux/dma/edma.h>
 #include <linux/irq.h>
 #include <linux/msi.h>
 #include <linux/pci.h>
@@ -144,6 +145,18 @@
 #define PCIE_MSIX_DOORBELL		0x948
 #define PCIE_MSIX_DOORBELL_PF_SHIFT	24
 
+/*
+ * eDMA CSRs. DW PCIe IP-core v4.70a and older had the eDMA registers accessible
+ * over the Port Logic registers space. Afterwords the unrolled mapping was
+ * introduced so eDMA and iATU could be accessed via a dedicated registers
+ * space.
+ */
+#define PCIE_DMA_VIEWPORT_BASE		0x970
+#define PCIE_DMA_UNROLL_BASE		0x80000
+#define PCIE_DMA_CTRL			0x008
+#define PCIE_DMA_NUM_WR_CHAN		GENMASK(3, 0)
+#define PCIE_DMA_NUM_RD_CHAN		GENMASK(19, 16)
+
 #define PCIE_PL_CHK_REG_CONTROL_STATUS			0xB20
 #define PCIE_PL_CHK_REG_CHK_REG_START			BIT(0)
 #define PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS		BIT(1)
@@ -160,6 +173,7 @@
  * this offset, if atu_base not set.
  */
 #define DEFAULT_DBI_ATU_OFFSET (0x3 << 20)
+#define DEFAULT_DBI_DMA_OFFSET (0x7 << 19)
 
 #define MAX_MSI_IRQS			256
 #define MAX_MSI_IRQS_PER_CTRL		32
@@ -171,6 +185,9 @@
 #define MAX_IATU_IN			256
 #define MAX_IATU_OUT			256
 
+/* Default eDMA LLP memory size */
+#define DMA_LLP_MEM_SIZE		PAGE_SIZE
+
 struct pcie_port;
 struct dw_pcie;
 struct dw_pcie_ep;
@@ -295,7 +312,7 @@ struct dw_pcie {
 	struct device		*dev;
 	void __iomem		*dbi_base;
 	void __iomem		*dbi_base2;
-	/* Used when iatu_unroll_enabled is true */
+	/* Used when {iatu,edma}_unroll_enabled is true */
 	void __iomem		*atu_base;
 	size_t			atu_size;
 	u32			num_ib_windows;
@@ -310,7 +327,9 @@ struct dw_pcie {
 	int			num_lanes;
 	int			link_gen;
 	u8			n_fts[2];
+	struct dw_edma_chip	edma;
 	bool			iatu_unroll_enabled: 1;
+	bool			edma_unroll_enabled: 1;
 	bool			io_cfg_atu_shared: 1;
 };
 
@@ -344,6 +363,8 @@ int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
 void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);
 void dw_pcie_setup(struct dw_pcie *pci);
 void dw_pcie_iatu_detect(struct dw_pcie *pci);
+int dw_pcie_edma_detect(struct dw_pcie *pci);
+void dw_pcie_edma_remove(struct dw_pcie *pci);
 
 static inline void dw_pcie_writel_dbi(struct dw_pcie *pci, u32 reg, u32 val)
 {
-- 
2.35.1


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

* Re: [PATCH 03/25] dma-direct: take dma-ranges/offsets into account in resource mapping
  2022-03-24  1:48 ` [PATCH 03/25] dma-direct: take dma-ranges/offsets into account in resource mapping Serge Semin
@ 2022-03-24 11:30   ` Robin Murphy
  2022-04-17 22:44     ` Serge Semin
  0 siblings, 1 reply; 79+ messages in thread
From: Robin Murphy @ 2022-03-24 11:30 UTC (permalink / raw)
  To: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Manivannan Sadhasivam,
	Christoph Hellwig, Marek Szyprowski, Vladimir Murzin
  Cc: Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel, iommu

On 2022-03-24 01:48, Serge Semin wrote:
> A basic device-specific linear memory mapping was introduced back in
> commit ("dma: Take into account dma_pfn_offset") as a single-valued offset
> preserved in the device.dma_pfn_offset field, which was initialized for
> instance by means of the "dma-ranges" DT property. Afterwards the
> functionality was extended to support more than one device-specific region
> defined in the device.dma_range_map list of maps. But all of these
> improvements concerned a single pointer, page or sg DMA-mapping methods,
> while the system resource mapping function turned to miss the
> corresponding modification. Thus the dma_direct_map_resource() method now
> just casts the CPU physical address to the device DMA address with no
> dma-ranges-based mapping taking into account, which is obviously wrong.
> Let's fix it by using the phys_to_dma_direct() method to get the
> device-specific bus address from the passed memory resource for the case
> of the directly mapped DMA.

It may not have been well-documented at the time, but this was largely 
intentional. The assumption based on known systems was that where 
dma_pfn_offset existed, it would *not* apply to peer MMIO addresses.

For instance, DTs for TI Keystone 2 platforms only describe an offset 
for RAM:

	dma-ranges = <0x80000000 0x8 0x00000000 0x80000000>;

but a DMA controller might also want to access something in the MMIO 
range 0x0-0x7fffffff, of which it still has an identical non-offset 
view. If a driver was previously using dma_map_resource() for that, it 
would now start getting DMA_MAPPING_ERROR because the dma_range_map 
exists but doesn't describe the MMIO region. I agree that in hindsight 
it's not an ideal situation, but it's how things have ended up, so at 
this point I'm wary of making potentially-breaking changes.

May I ask what exactly your setup looks like, if you have a DMA 
controller with an offset view of its "own" MMIO space?

Thanks,
Robin.

> Fixes: 25f1e1887088 ("dma: Take into account dma_pfn_offset")
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>   kernel/dma/direct.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
> index 50f48e9e4598..9ce8192b29ab 100644
> --- a/kernel/dma/direct.c
> +++ b/kernel/dma/direct.c
> @@ -497,7 +497,7 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
>   dma_addr_t dma_direct_map_resource(struct device *dev, phys_addr_t paddr,
>   		size_t size, enum dma_data_direction dir, unsigned long attrs)
>   {
> -	dma_addr_t dma_addr = paddr;
> +	dma_addr_t dma_addr = phys_to_dma_direct(dev, paddr);
>   
>   	if (unlikely(!dma_capable(dev, dma_addr, size, false))) {
>   		dev_err_once(dev,

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

* Re: [PATCH 01/25] dmaengine: dw-edma: Drop dma_slave_config.direction field usage
  2022-03-24  1:48 ` [PATCH 01/25] dmaengine: dw-edma: Drop dma_slave_config.direction field usage Serge Semin
@ 2022-03-24 13:30   ` Manivannan Sadhasivam
  2022-04-05 11:15     ` Serge Semin
  0 siblings, 1 reply; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-24 13:30 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:12AM +0300, Serge Semin wrote:
> The dma_slave_config.direction field usage in the DW eDMA driver has been
> introduced in the commit bd96f1b2f43a ("dmaengine: dw-edma: support local
> dma device transfer semantics"). Mainly the change introduced there was
> correct (indeed DEV_TO_MEM means using RD-channel and MEM_TO_DEV -
> WR-channel for the case of having eDMA accessed locally from
> CPU/Application side), but providing an additional
> MEM_TO_MEM/DEV_TO_DEV-based semantics was quite redundant if not to say
> potentially harmful (when it comes to removing the denoted field). First
> of all since the dma_slave_config.direction field has been marked as
> obsolete (see [1] and the structure dc [2]) and will be discarded in
> future, using it especially in a non-standard way is discouraged. Secondly
> in accordance with the commit denoted above the default
> dw_edma_device_transfer() semantics has been changed despite what it's
> message said. So claiming that the method was left backward compatible was
> wrong.
> 
> Anyway let's fix the problems denoted above and simplify the
> dw_edma_device_transfer() method by dropping the parsing of the
> DMA-channel direction field. Instead of having that implicit
> dma_slave_config.direction field semantic we can use the recently added
> DW_EDMA_CHIP_LOCAL flag to distinguish between the local and remote DW
> eDMA setups thus preserving both cases support. In addition to that an
> ASCII-figure has been added to clarify the complication out.
> 
> [1] Documentation/driver-api/dmaengine/provider.rst
> [2] include/linux/dmaengine.h: dma_slave_config.direction
> 
> Co-developed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> 
> ---
> 
> In accordance with agreement with Frank and Manivannan this patch is
> supposed to be moved to the series:
> Link: https://lore.kernel.org/dmaengine/20220310192457.3090-1-Frank.Li@nxp.com/
> in place of the patch:
> [PATCH v5 6/9] dmaengine: dw-edma: Don't rely on the deprecated "direction" member
> Link: https://lore.kernel.org/dmaengine/20220310192457.3090-7-Frank.Li@nxp.com/
> ---
>  drivers/dma/dw-edma/dw-edma-core.c | 49 +++++++++++++++++++++---------
>  1 file changed, 34 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 5be8a5944714..e9e32ed74aa9 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -339,21 +339,40 @@ 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;
> -		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;
> +	/*
> +	 * Local Root Port/End-point              Remote End-point
> +	 * +-----------------------+ PCIe bus +----------------------+
> +	 * |                       |    +-+   |                      |
> +	 * |    DEV_TO_MEM   Rx Ch <----+ +---+ Tx Ch  DEV_TO_MEM    |
> +	 * |                       |    | |   |                      |
> +	 * |    MEM_TO_DEV   Tx Ch +----+ +---> Rx Ch  MEM_TO_DEV    |
> +	 * |                       |    +-+   |                      |
> +	 * +-----------------------+          +----------------------+
> +	 *
> +	 * 1. Normal logic:
> +	 * If eDMA is embedded into the DW PCIe RP/EP and controlled from the
> +	 * CPU/Application side, the Rx channel (EDMA_DIR_READ) will be used
> +	 * for the device read operations (DEV_TO_MEM) and the Tx channel
> +	 * (EDMA_DIR_WRITE) - for the write operations (MEM_TO_DEV).
> +	 *
> +	 * 2. Inverted logic:
> +	 * If eDMA is embedded into a Remote PCIe EP and is controlled by the
> +	 * MWr/MRd TLPs sent from the CPU's PCIe host controller, the Tx
> +	 * channel (EDMA_DIR_WRITE) will be used for the device read operations
> +	 * (DEV_TO_MEM) and the Rx channel (EDMA_DIR_READ) - for the write
> +	 * operations (MEM_TO_DEV).
> +	 *
> +	 * It is the client driver responsibility to choose a proper channel
> +	 * for the DMA transfers.
> +	 */

I think it'd be good to document this using some form in "enum dw_edma_dir"
declaration.

Thanks,
Mani

> +	if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
> +		if ((chan->dir == EDMA_DIR_READ && dir != DMA_DEV_TO_MEM) ||
> +		    (chan->dir == EDMA_DIR_WRITE && dir != DMA_MEM_TO_DEV))
> +			return NULL;
> +	} else {
> +		if ((chan->dir == EDMA_DIR_WRITE && dir != DMA_DEV_TO_MEM) ||
> +		    (chan->dir == EDMA_DIR_READ && dir != DMA_MEM_TO_DEV))
> +			return NULL;
>  	}
>  
>  	if (xfer->type == EDMA_XFER_CYCLIC) {
> -- 
> 2.35.1
> 

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

* Re: [PATCH 04/25] dmaengine: Fix dma_slave_config.dst_addr description
  2022-03-24  1:48 ` [PATCH 04/25] dmaengine: Fix dma_slave_config.dst_addr description Serge Semin
@ 2022-03-24 14:08   ` Manivannan Sadhasivam
  2022-03-31  5:38     ` Vinod Koul
  0 siblings, 1 reply; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-24 14:08 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:15AM +0300, Serge Semin wrote:
> Most likely due to a copy-paste mistake the dst_addr member of the
> dma_slave_config structure has been marked as ignored if the !source!
> address belong to the memory. That is relevant to the src_addr field of
> the structure while the dst_addr field as containing a destination device
> address is supposed to be ignored if the destination is the CPU memory.
> Let's fix the field description accordingly.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

One suggestion below.

> ---
>  include/linux/dmaengine.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index 842d4f7ca752..f204ea16ac1c 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -395,7 +395,7 @@ enum dma_slave_buswidth {
>   * should be read (RX), if the source is memory this argument is
>   * ignored.
>   * @dst_addr: this is the physical address where DMA slave data
> - * should be written (TX), if the source is memory this argument
> + * should be written (TX), if the destination is memory this argument

Should we rename "memory" to "local memory" or something similar?

Thanks,
Mani

>   * is ignored.
>   * @src_addr_width: this is the width in bytes of the source (RX)
>   * register where DMA data shall be read. If the source
> -- 
> 2.35.1
> 

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

* Re: [PATCH 05/25] dmaengine: dw-edma: Convert ll/dt phys-address to PCIe bus/DMA address
  2022-03-24  1:48 ` [PATCH 05/25] dmaengine: dw-edma: Convert ll/dt phys-address to PCIe bus/DMA address Serge Semin
@ 2022-03-24 16:23   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-24 16:23 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:16AM +0300, Serge Semin wrote:
> In accordance with the dw_edma_region.paddr field semantics it is supposed
> to be initialized with a memory base address visible by the DW eDMA
> controller. If the DMA engine is embedded into the DW PCIe Host/EP
> controller, then the address should belong to the Local CPU/Application
> memory. If eDMA is remotely accessible across the PCIe bus via the PCIe
> memory IOs, then the address needs to be a part of the PCIe bus memory
> space. The later case hasn't been well covered in the corresponding
> glue-driver. Since in general the PCIe memory space doesn't have to match
> the CPU memory space and the pci_dev.resource[] arrays contain the
> resources defined in the CPU memory space, a proper conversion needs to be
> performed, otherwise either the driver won't properly work or much worse
> the memory corruption will happen. The conversion can be done by means of
> the pci_bus_address() method. Let's use it to retrieve the LL, DT and CSRs
> PCIe memory ranges.
> 
> Note in addition to that we need to extend the dw_edma_region.paddr field
> size. The field normally contains a memory range base address to be set in
> the DW eDMA Linked-List pointer register or as a base address of the
> Linked-List data buffer. In accordance with [1] the LL range is supposed
> to be created in the Local CPU/Application memory, but depending on the DW
> eDMA utilization the memory can be created as a part of the PCIe bus
> address space (as in the case of the DW PCIe EP prototype kit). Thus in
> the former case the dw_edma_region.paddr field should have the dma_addr_t
> type, while in the later one - pci_bus_addr_t. Seeing the corresponding
> CSRs are always 64-bits wide let's convert the dw_edma_region.paddr field
> type to be u64 and let the client code logic to make sure it has a valid
> address visible by the DW eDMA controller. For instance the DW eDMA PCIe
> glue-driver initializes the field with the addresses from the PCIe bus
> memory space.
> 
> [1] DesignWare Cores PCI Express Controller Databook - DWC PCIe Root Port,
>     v.5.40a, March 2019, p.1103
> 
> Fixes: 41aaff2a2ac0 ("dmaengine: Add Synopsys eDMA IP PCIe glue-logic")
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

Thanks,
Mani

> ---
>  drivers/dma/dw-edma/dw-edma-pcie.c | 8 ++++----
>  include/linux/dma/edma.h           | 2 +-
>  2 files changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> index d6b5e2463884..04c95cba1244 100644
> --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> @@ -231,7 +231,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  			return -ENOMEM;
>  
>  		ll_region->vaddr += ll_block->off;
> -		ll_region->paddr = pdev->resource[ll_block->bar].start;
> +		ll_region->paddr = pci_bus_address(pdev, ll_block->bar);
>  		ll_region->paddr += ll_block->off;
>  		ll_region->sz = ll_block->sz;
>  
> @@ -240,7 +240,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  			return -ENOMEM;
>  
>  		dt_region->vaddr += dt_block->off;
> -		dt_region->paddr = pdev->resource[dt_block->bar].start;
> +		dt_region->paddr = pci_bus_address(pdev, dt_block->bar);
>  		dt_region->paddr += dt_block->off;
>  		dt_region->sz = dt_block->sz;
>  	}
> @@ -256,7 +256,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  			return -ENOMEM;
>  
>  		ll_region->vaddr += ll_block->off;
> -		ll_region->paddr = pdev->resource[ll_block->bar].start;
> +		ll_region->paddr = pci_bus_address(pdev, ll_block->bar);
>  		ll_region->paddr += ll_block->off;
>  		ll_region->sz = ll_block->sz;
>  
> @@ -265,7 +265,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  			return -ENOMEM;
>  
>  		dt_region->vaddr += dt_block->off;
> -		dt_region->paddr = pdev->resource[dt_block->bar].start;
> +		dt_region->paddr = pci_bus_address(pdev, dt_block->bar);
>  		dt_region->paddr += dt_block->off;
>  		dt_region->sz = dt_block->sz;
>  	}
> diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> index 8897f8a79b52..5abac9640a4e 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -18,7 +18,7 @@
>  struct dw_edma;
>  
>  struct dw_edma_region {
> -	phys_addr_t	paddr;
> +	u64		paddr;
>  	void __iomem	*vaddr;
>  	size_t		sz;
>  };
> -- 
> 2.35.1
> 

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

* Re: [PATCH 06/25] dmaengine: dw-edma: Fix missing src/dst address of the interleaved xfers
  2022-03-24  1:48 ` [PATCH 06/25] dmaengine: dw-edma: Fix missing src/dst address of the interleaved xfers Serge Semin
@ 2022-03-24 16:26   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-24 16:26 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:17AM +0300, Serge Semin wrote:
> The interleaved DMA transfers support was added in the commit 85e7518f42c8
> ("dmaengine: dw-edma: Add device_prep_interleave_dma() support"). It
> seems like the support was broken from the very beginning. Depending on
> the selected channel either source or destination address are left
> uninitialized which was obviously wrong. I don't really know how come the
> original modification was working for the commit author. Anyway let's fix
> it by initializing the destination address of the eDMA burst descriptors
> for the DEV_TO_MEM interleaved operations and by initializing the source
> address of the eDMA burst descriptors for the MEM_TO_DEV interleaved
> operations.
> 
> Fixes: 85e7518f42c8 ("dmaengine: dw-edma: Add device_prep_interleave_dma() support")
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

Thanks,
Mani

> ---
>  drivers/dma/dw-edma/dw-edma-core.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 519d4b3c9fa0..2010d7f8191f 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -456,6 +456,8 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
>  				 * and destination addresses are increased
>  				 * by the same portion (data length)
>  				 */
> +			} else if (xfer->type == EDMA_XFER_INTERLEAVED) {
> +				burst->dar = dst_addr;
>  			}
>  		} else {
>  			burst->dar = dst_addr;
> @@ -471,6 +473,8 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
>  				 * and destination addresses are increased
>  				 * by the same portion (data length)
>  				 */
> +			}  else if (xfer->type == EDMA_XFER_INTERLEAVED) {
> +				burst->sar = src_addr;
>  			}
>  		}
>  
> -- 
> 2.35.1
> 

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

* Re: [PATCH 07/25] dmaengine: dw-edma: Don't permit non-inc interleaved xfers
  2022-03-24  1:48 ` [PATCH 07/25] dmaengine: dw-edma: Don't permit non-inc " Serge Semin
@ 2022-03-24 17:15   ` Manivannan Sadhasivam
  2022-04-17 22:59     ` Serge Semin
  0 siblings, 1 reply; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-24 17:15 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:18AM +0300, Serge Semin wrote:
> DW eDMA controller always increments both source and destination
> addresses. Permitting DMA interleaved transfers with no src_inc/dst_inc
> flags set may lead to unexpected behaviour for the device users. Let's fix
> that by terminating the interleaved transfers if at least one of the
> dma_interleaved_template.{src_inc,dst_inc} flag is initialized with false
> value. Note in addition to that we need we need to increase the source and
> destination addresses accordingly after each iteration.
> 

Can you please point me where this gets documented in databook?

Thanks,
Mani

> Fixes: 85e7518f42c8 ("dmaengine: dw-edma: Add device_prep_interleave_dma() support")
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/dma/dw-edma/dw-edma-core.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 2010d7f8191f..f41bde27795c 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -386,6 +386,8 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
>  			return NULL;
>  		if (xfer->xfer.il->numf > 0 && xfer->xfer.il->frame_size > 0)
>  			return NULL;
> +		if (!xfer->xfer.il->src_inc || !xfer->xfer.il->dst_inc)
> +			return NULL;
>  	} else {
>  		return NULL;
>  	}
> @@ -485,15 +487,13 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
>  			struct dma_interleaved_template *il = xfer->xfer.il;
>  			struct data_chunk *dc = &il->sgl[i];
>  
> -			if (il->src_sgl) {
> -				src_addr += burst->sz;
> +			src_addr += burst->sz;
> +			if (il->src_sgl)
>  				src_addr += dmaengine_get_src_icg(il, dc);
> -			}
>  
> -			if (il->dst_sgl) {
> -				dst_addr += burst->sz;
> +			dst_addr += burst->sz;
> +			if (il->dst_sgl)
>  				dst_addr += dmaengine_get_dst_icg(il, dc);
> -			}
>  		}
>  	}
>  
> -- 
> 2.35.1
> 

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

* Re: [PATCH 09/25] dmaengine: dw-edma: Add CPU to PCIe bus address translation
  2022-03-24  1:48 ` [PATCH 09/25] dmaengine: dw-edma: Add CPU to PCIe bus address translation Serge Semin
@ 2022-03-24 17:25   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-24 17:25 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:20AM +0300, Serge Semin wrote:
> Starting from commit 9575632052ba ("dmaengine: make slave address
> physical") the source and destination addresses of the DMA-slave device
> have been converted to being defined in CPU address space. It's DMA-device
> driver responsibility to properly convert them to the reachable DMA bus
> spaces. In case of the DW eDMA device, the source or destination
> peripheral (slave) devices reside PCIe bus space. Thus we need to perform
> the PCIe Host/EP windows-based (i.e. ranges DT-property) addresses
> translation otherwise the eDMA transactions won't work as expected (or can
> be even harmful) in case if the CPU and PCIe address spaces don't match.
> 
> Note 1. Even though the DMA interleaved template has both source and
> destination addresses declared of dma_addr_t type only CPU memory range is
> supposed to be mapped in a way so to be seen by the DMA device since it's
> a subject of the DMA getting towards the system side. The device part must
> not be mapped since slave device resides in the PCIe bus space, which
> isn't affected by IOMMUs or iATU translations. DW PCIe eDMA generates
> corresponding MWr/MRd TLPs on its own.
> 
> Note 2. This functionality is mainly required for the remote eDMA setup
> since the CPU address must be manually translated into the PCIe bus space
> before being written to LLI.{SAR,DAR}. If eDMA is embedded into the
> locally accessible DW PCIe RP/EP software-based translation isn't required
> since it will be done by hardware by means of the Outbound iATU as long as
> the DMA_BYPASS flag is cleared. If the later flag is set or there is no
> Outbound iATU entry found to which the SAR or DAR falls in (for Read and
> Write channel respectfully), there won't be any translation performed but
> DMA will proceed with the corresponding source/destination address as is.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

Thanks,
Mani

> ---
>  drivers/dma/dw-edma/dw-edma-core.c | 18 +++++++++++++++++-
>  include/linux/dma/edma.h           | 15 +++++++++++++++
>  2 files changed, 32 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 97743fe44ebf..418b201fef67 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -40,6 +40,17 @@ struct dw_edma_desc *vd2dw_edma_desc(struct virt_dma_desc *vd)
>  	return container_of(vd, struct dw_edma_desc, vd);
>  }
>  
> +static inline
> +u64 dw_edma_get_pci_address(struct dw_edma_chan *chan, phys_addr_t cpu_addr)
> +{
> +	struct dw_edma_chip *chip = chan->dw->chip;
> +
> +	if (chip->ops->pci_address)
> +		return chip->ops->pci_address(chip->dev, cpu_addr);
> +
> +	return cpu_addr;
> +}
> +
>  static struct dw_edma_burst *dw_edma_alloc_burst(struct dw_edma_chunk *chunk)
>  {
>  	struct dw_edma_burst *burst;
> @@ -328,11 +339,11 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
>  {
>  	struct dw_edma_chan *chan = dchan2dw_edma_chan(xfer->dchan);
>  	enum dma_transfer_direction dir = xfer->direction;
> -	phys_addr_t src_addr, dst_addr;
>  	struct scatterlist *sg = NULL;
>  	struct dw_edma_chunk *chunk;
>  	struct dw_edma_burst *burst;
>  	struct dw_edma_desc *desc;
> +	u64 src_addr, dst_addr;
>  	size_t fsz = 0;
>  	u32 cnt = 0;
>  	int i;
> @@ -407,6 +418,11 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
>  		dst_addr = chan->config.dst_addr;
>  	}
>  
> +	if (dir == DMA_DEV_TO_MEM)
> +		src_addr = dw_edma_get_pci_address(chan, (phys_addr_t)src_addr);
> +	else
> +		dst_addr = dw_edma_get_pci_address(chan, (phys_addr_t)dst_addr);
> +
>  	if (xfer->type == EDMA_XFER_CYCLIC) {
>  		cnt = xfer->xfer.cyclic.cnt;
>  	} else if (xfer->type == EDMA_XFER_SCATTER_GATHER) {
> diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> index 5abac9640a4e..5cc87cfdd685 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -23,8 +23,23 @@ struct dw_edma_region {
>  	size_t		sz;
>  };
>  
> +/**
> + * struct dw_edma_core_ops - platform-specific eDMA methods
> + * @irq_vector:		Get IRQ number of the passed eDMA channel. Note the
> + *                      method accepts the channel id in the end-to-end
> + *                      numbering with the eDMA write channels being placed
> + *                      first in the row.
> + * @pci_address:	Get PCIe bus address corresponding to the passed CPU
> + *			address. Note there is no need in specifying this
> + *			function if the address translation is performed by
> + *			the DW PCIe RP/EP controller with the DW eDMA device in
> + *			subject and DMA_BYPASS isn't set for all the outbound
> + *			iATU windows. That will be done by the controller
> + *			automatically.
> + */
>  struct dw_edma_core_ops {
>  	int (*irq_vector)(struct device *dev, unsigned int nr);
> +	u64 (*pci_address)(struct device *dev, phys_addr_t cpu_addr);
>  };
>  
>  enum dw_edma_map_format {
> -- 
> 2.35.1
> 

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

* Re: [PATCH 10/25] dmaengine: dw-edma: Add PCIe bus address getter to the remote EP glue-driver
  2022-03-24  1:48 ` [PATCH 10/25] dmaengine: dw-edma: Add PCIe bus address getter to the remote EP glue-driver Serge Semin
@ 2022-03-24 17:41   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-24 17:41 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:21AM +0300, Serge Semin wrote:
> In general the Synopsys PCIe EndPoint IP prototype kit can be attached to
> a PCIe bus with any PCIe Host controller including to the one with
> distinctive from CPU address space. Due to that we need to make sure that
> the source and destination addresses of the DMA-slave devices are properly
> converted to the PCIe bus address space, otherwise the DMA transaction
> will not only work as expected, but may cause the memory corruption with
> subsequent system crash. Let's do that by introducing a new
> dw_edma_pcie_address() method defined in the dw-edma-pcie.c, which will
> perform the denoted translation by using the pcibios_resource_to_bus()
> method.
> 
> Fixes: 41aaff2a2ac0 ("dmaengine: Add Synopsys eDMA IP PCIe glue-logic")
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> 

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

Thanks,
Mani

> ---
> 
> Note this patch depends on the patch "dmaengine: dw-edma: Add CPU to PCIe
> bus address translation" from this series.
> ---
>  drivers/dma/dw-edma/dw-edma-pcie.c | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> index 04c95cba1244..f530bacfd716 100644
> --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> @@ -95,8 +95,23 @@ static int dw_edma_pcie_irq_vector(struct device *dev, unsigned int nr)
>  	return pci_irq_vector(to_pci_dev(dev), nr);
>  }
>  
> +static u64 dw_edma_pcie_address(struct device *dev, phys_addr_t cpu_addr)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +	struct pci_bus_region region;
> +	struct resource res = {
> +		.flags = IORESOURCE_MEM,
> +		.start = cpu_addr,
> +		.end = cpu_addr,
> +	};
> +
> +	pcibios_resource_to_bus(pdev->bus, &region, &res);
> +	return region.start;
> +}
> +
>  static const struct dw_edma_core_ops dw_edma_pcie_core_ops = {
>  	.irq_vector = dw_edma_pcie_irq_vector,
> +	.pci_address = dw_edma_pcie_address,
>  };
>  
>  static void dw_edma_pcie_get_vsec_dma_data(struct pci_dev *pdev,
> -- 
> 2.35.1
> 

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

* Re: [PATCH 11/25] dmaengine: dw-edma: Drop chancnt initialization
  2022-03-24  1:48 ` [PATCH 11/25] dmaengine: dw-edma: Drop chancnt initialization Serge Semin
@ 2022-03-24 17:42   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-24 17:42 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:22AM +0300, Serge Semin wrote:
> DMA device drivers aren't supposed to initialize the dma_device.chancnt
> field. It will be done by the DMA-engine core in accordance with number of
> added virtual DMA-channels. Pre-initializing it with some value causes
> having a wrong number of channels printed in the device summary.
> 
> Fixes: e63d79d1ffcd ("dmaengine: Add Synopsys eDMA IP core driver")
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

Thanks,
Mani

> ---
>  drivers/dma/dw-edma/dw-edma-core.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 418b201fef67..cefa73412bf7 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -823,7 +823,6 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  	dma->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
>  	dma->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
>  	dma->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
> -	dma->chancnt = cnt;
>  
>  	/* Set DMA channel callbacks */
>  	dma->dev = chip->dev;
> -- 
> 2.35.1
> 

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

* Re: [PATCH 12/25] dmaengine: dw-edma: Fix DebugFS reg entry type
  2022-03-24  1:48 ` [PATCH 12/25] dmaengine: dw-edma: Fix DebugFS reg entry type Serge Semin
@ 2022-03-24 17:48   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-24 17:48 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:23AM +0300, Serge Semin wrote:
> debugfs_entries structure declared in the dw-edma-v0-debugfs.c module
> contains the DebugFS node' register address. The address is declared as
> dma_addr_t type, but first it's assigned with virtual CPU IOMEM address
> and then it's cast back to the virtual address. Even though the castes
> sandwich will unlikely cause any problem since normally DMA address is at
> least of the same size as the CPU virtual address, it's at the very least
> redundant if not to say logically incorrect. Let's fix it by just stop
> casting the pointer back and worth and just preserve the address as a
> pointer to void with __iomem qualifier.
> 
> Fixes: 305aebeff879 ("dmaengine: Add Synopsys eDMA IP version 0 debugfs support")
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

Thanks,
Mani

> ---
>  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> index 3a899f7f4e8d..12845a2dc016 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> @@ -14,7 +14,7 @@
>  #include "dw-edma-core.h"
>  
>  #define REGS_ADDR(name) \
> -	((void __force *)&regs->name)
> +	((void __iomem *)&regs->name)
>  #define REGISTER(name) \
>  	{ #name, REGS_ADDR(name) }
>  
> @@ -48,12 +48,13 @@ static struct {
>  
>  struct debugfs_entries {
>  	const char				*name;
> -	dma_addr_t				*reg;
> +	void __iomem				*reg;
>  };
>  
>  static int dw_edma_debugfs_u32_get(void *data, u64 *val)
>  {
> -	void __iomem *reg = (void __force __iomem *)data;
> +	void __iomem *reg = data;
> +
>  	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
>  	    reg >= (void __iomem *)&regs->type.legacy.ch) {
>  		void __iomem *ptr = &regs->type.legacy.ch;
> -- 
> 2.35.1
> 

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

* Re: [PATCH 13/25] dmaengine: dw-edma: Stop checking debugfs_create_*() return value
  2022-03-24  1:48 ` [PATCH 13/25] dmaengine: dw-edma: Stop checking debugfs_create_*() return value Serge Semin
@ 2022-03-24 18:12   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-24 18:12 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:24AM +0300, Serge Semin wrote:
> First of all they never return NULL. So checking their return value for
> being not NULL just pointless. Secondly the DebugFS subsystem is designed
> in a way to be used as simple as possible. So if one of the
> debugfs_create_*() method in a hierarchy fails, the following methods will
> just silently return the passed erroneous parental dentry. Finally the
> code is supposed to be working no matter whether anything DebugFS-related
> fails. So in order to make code simpler and DebugFS-independent let's drop
> the debugfs_create_*() methods return value checking in the same way as
> the most of the kernel drivers do.
> 
> Note in order to preserve some memory space we suggest to skip the DebugFS
> nodes initialization if the file system in unavailable.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

Thanks,
Man

> ---
>  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 20 +++++---------------
>  1 file changed, 5 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> index 12845a2dc016..808eed212be8 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> @@ -100,9 +100,8 @@ static void dw_edma_debugfs_create_x32(const struct debugfs_entries entries[],
>  	int i;
>  
>  	for (i = 0; i < nr_entries; i++) {
> -		if (!debugfs_create_file_unsafe(entries[i].name, 0444, dir,
> -						entries[i].reg,	&fops_x32))
> -			break;
> +		debugfs_create_file_unsafe(entries[i].name, 0444, dir,
> +					   entries[i].reg, &fops_x32);
>  	}
>  }
>  
> @@ -168,8 +167,6 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
>  	char name[16];
>  
>  	regs_dir = debugfs_create_dir(WRITE_STR, dir);
> -	if (!regs_dir)
> -		return;
>  
>  	nr_entries = ARRAY_SIZE(debugfs_regs);
>  	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
> @@ -184,8 +181,6 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
>  		snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
>  
>  		ch_dir = debugfs_create_dir(name, regs_dir);
> -		if (!ch_dir)
> -			return;
>  
>  		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].wr, ch_dir);
>  
> @@ -237,8 +232,6 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
>  	char name[16];
>  
>  	regs_dir = debugfs_create_dir(READ_STR, dir);
> -	if (!regs_dir)
> -		return;
>  
>  	nr_entries = ARRAY_SIZE(debugfs_regs);
>  	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
> @@ -253,8 +246,6 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
>  		snprintf(name, sizeof(name), "%s:%d", CHANNEL_STR, i);
>  
>  		ch_dir = debugfs_create_dir(name, regs_dir);
> -		if (!ch_dir)
> -			return;
>  
>  		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].rd, ch_dir);
>  
> @@ -273,8 +264,6 @@ static void dw_edma_debugfs_regs(void)
>  	int nr_entries;
>  
>  	regs_dir = debugfs_create_dir(REGISTERS_STR, dw->debugfs);
> -	if (!regs_dir)
> -		return;
>  
>  	nr_entries = ARRAY_SIZE(debugfs_regs);
>  	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
> @@ -285,6 +274,9 @@ static void dw_edma_debugfs_regs(void)
>  
>  void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
>  {
> +	if (!debugfs_initialized())
> +		return;
> +
>  	dw = chip->dw;
>  	if (!dw)
>  		return;
> @@ -294,8 +286,6 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
>  		return;
>  
>  	dw->debugfs = debugfs_create_dir(dw->name, NULL);
> -	if (!dw->debugfs)
> -		return;
>  
>  	debugfs_create_u32("mf", 0444, dw->debugfs, &dw->chip->mf);
>  	debugfs_create_u16("wr_ch_cnt", 0444, dw->debugfs, &dw->wr_ch_cnt);
> -- 
> 2.35.1
> 

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

* Re: [PATCH 14/25] dmaengine: dw-edma: Add dw_edma prefix to the DebugFS nodes descriptor
  2022-03-24  1:48 ` [PATCH 14/25] dmaengine: dw-edma: Add dw_edma prefix to the DebugFS nodes descriptor Serge Semin
@ 2022-03-24 18:14   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-24 18:14 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:25AM +0300, Serge Semin wrote:
> The rest of the locally defined and used methods and structures have
> dw_edma prefix in their names. It's right in accordance with the kernel
> coding style to follow the locally defined rule of naming. Let's add that
> prefix to the debugfs_entries structure too especially seeing it's name
> may be confusing as if that structure belongs to the global DebugFS space.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

Thanks,
Man

> ---
>  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 18 +++++++++---------
>  1 file changed, 9 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> index 808eed212be8..afd519d9568b 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> @@ -46,7 +46,7 @@ static struct {
>  	void					__iomem *end;
>  } lim[2][EDMA_V0_MAX_NR_CH];
>  
> -struct debugfs_entries {
> +struct dw_edma_debugfs_entry {
>  	const char				*name;
>  	void __iomem				*reg;
>  };
> @@ -94,7 +94,7 @@ static int dw_edma_debugfs_u32_get(void *data, u64 *val)
>  }
>  DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");
>  
> -static void dw_edma_debugfs_create_x32(const struct debugfs_entries entries[],
> +static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry entries[],
>  				       int nr_entries, struct dentry *dir)
>  {
>  	int i;
> @@ -108,8 +108,7 @@ static void dw_edma_debugfs_create_x32(const struct debugfs_entries entries[],
>  static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs __iomem *regs,
>  				    struct dentry *dir)
>  {
> -	int nr_entries;
> -	const struct debugfs_entries debugfs_regs[] = {
> +	const struct dw_edma_debugfs_entry debugfs_regs[] = {
>  		REGISTER(ch_control1),
>  		REGISTER(ch_control2),
>  		REGISTER(transfer_size),
> @@ -120,6 +119,7 @@ static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs __iomem *regs,
>  		REGISTER(llp.lsb),
>  		REGISTER(llp.msb),
>  	};
> +	int nr_entries;
>  
>  	nr_entries = ARRAY_SIZE(debugfs_regs);
>  	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, dir);
> @@ -127,7 +127,7 @@ static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs __iomem *regs,
>  
>  static void dw_edma_debugfs_regs_wr(struct dentry *dir)
>  {
> -	const struct debugfs_entries debugfs_regs[] = {
> +	const struct dw_edma_debugfs_entry debugfs_regs[] = {
>  		/* eDMA global registers */
>  		WR_REGISTER(engine_en),
>  		WR_REGISTER(doorbell),
> @@ -148,7 +148,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
>  		WR_REGISTER(ch67_imwr_data),
>  		WR_REGISTER(linked_list_err_en),
>  	};
> -	const struct debugfs_entries debugfs_unroll_regs[] = {
> +	const struct dw_edma_debugfs_entry debugfs_unroll_regs[] = {
>  		/* eDMA channel context grouping */
>  		WR_REGISTER_UNROLL(engine_chgroup),
>  		WR_REGISTER_UNROLL(engine_hshake_cnt.lsb),
> @@ -191,7 +191,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
>  
>  static void dw_edma_debugfs_regs_rd(struct dentry *dir)
>  {
> -	const struct debugfs_entries debugfs_regs[] = {
> +	const struct dw_edma_debugfs_entry debugfs_regs[] = {
>  		/* eDMA global registers */
>  		RD_REGISTER(engine_en),
>  		RD_REGISTER(doorbell),
> @@ -213,7 +213,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
>  		RD_REGISTER(ch45_imwr_data),
>  		RD_REGISTER(ch67_imwr_data),
>  	};
> -	const struct debugfs_entries debugfs_unroll_regs[] = {
> +	const struct dw_edma_debugfs_entry debugfs_unroll_regs[] = {
>  		/* eDMA channel context grouping */
>  		RD_REGISTER_UNROLL(engine_chgroup),
>  		RD_REGISTER_UNROLL(engine_hshake_cnt.lsb),
> @@ -256,7 +256,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
>  
>  static void dw_edma_debugfs_regs(void)
>  {
> -	const struct debugfs_entries debugfs_regs[] = {
> +	const struct dw_edma_debugfs_entry debugfs_regs[] = {
>  		REGISTER(ctrl_data_arb_prior),
>  		REGISTER(ctrl),
>  	};
> -- 
> 2.35.1
> 

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

* Re: [PATCH 15/25] dmaengine: dw-edma: Convert DebugFS descs to being kz-allocated
  2022-03-24  1:48 ` [PATCH 15/25] dmaengine: dw-edma: Convert DebugFS descs to being kz-allocated Serge Semin
@ 2022-03-25  6:03   ` Manivannan Sadhasivam
  2022-03-25  6:42     ` Manivannan Sadhasivam
  2022-04-18  7:17     ` Serge Semin
  0 siblings, 2 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-25  6:03 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:26AM +0300, Serge Semin wrote:
> Currently all the DW eDMA DebugFS nodes descriptors are allocated on
> stack, while the DW eDMA driver private data and CSR limits are statically
> preserved. Such design won't work for the multi-eDMA platforms.

Can you please explain why?

> As a
> preparation to adding the multi-eDMA system setups support we need to have
> each DebugFS node separately allocated and described. Afterwards we'll put
> an addition info there like Read/Write channel flag, channel ID, DW eDMA
> private data reference.
> 
> Note this conversion is mainly required due to having the legacy DW eDMA
> controllers with indirect Read/Write channels context CSRs access. If we
> didn't need to have a synchronized access to these registers the DebugFS
> code of the driver would have been much simpler.
> 

I fail to understand how this change is beneficial or the exact issue.

> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 15 ++++++++++++---
>  1 file changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> index afd519d9568b..7eb0147912fa 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> @@ -53,7 +53,8 @@ struct dw_edma_debugfs_entry {
>  
>  static int dw_edma_debugfs_u32_get(void *data, u64 *val)
>  {
> -	void __iomem *reg = data;
> +	struct dw_edma_debugfs_entry __iomem *entry = data;

Why the entry has to be of __iomem?

Thanks,
Mani

> +	void __iomem *reg = entry->reg;
>  
>  	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
>  	    reg >= (void __iomem *)&regs->type.legacy.ch) {
> @@ -94,14 +95,22 @@ static int dw_edma_debugfs_u32_get(void *data, u64 *val)
>  }
>  DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");
>  
> -static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry entries[],
> +static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry ini[],
>  				       int nr_entries, struct dentry *dir)
>  {
> +	struct dw_edma_debugfs_entry *entries;
>  	int i;
>  
> +	entries = devm_kcalloc(dw->chip->dev, nr_entries, sizeof(*entries),
> +			       GFP_KERNEL);
> +	if (!entries)
> +		return;
> +
>  	for (i = 0; i < nr_entries; i++) {
> +		entries[i] = ini[i];
> +
>  		debugfs_create_file_unsafe(entries[i].name, 0444, dir,
> -					   entries[i].reg, &fops_x32);
> +					   &entries[i], &fops_x32);
>  	}
>  }
>  
> -- 
> 2.35.1
> 

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

* Re: [PATCH 16/25] dmaengine: dw-edma: Simplify the DebugFS context CSRs init procedure
  2022-03-24  1:48 ` [PATCH 16/25] dmaengine: dw-edma: Simplify the DebugFS context CSRs init procedure Serge Semin
@ 2022-03-25  6:27   ` Manivannan Sadhasivam
  2022-03-25  6:31     ` Manivannan Sadhasivam
  2022-04-18  8:23     ` Serge Semin
  0 siblings, 2 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-25  6:27 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:27AM +0300, Serge Semin wrote:
> DW eDMA v4.70a and older have the read and write channels context CSRs
> indirectly accessible. It means the CSRs like Channel Control, Xfer size,
> SAR, DAR and LLP address are accessed over at a fixed MMIO address, but
> their reference to the corresponding channel is determined by the Viewport
> CSR. In order to have a coherent access to these registers the CSR IOs are
> supposed to be protected with a spin-lock. DW eDMA v4.80a and newer
> normally have unrolled Read/Write channel context registers. That is all
> CSRs denoted before are directly mapped in the controller MMIO space.
> 
> Since both normal and viewport-based registers are exposed via the DebugFS
> nodes, the original code author decided to implement an algorithm based on
> the unrolled CSRs mapping with the viewport addresses recalculation if
> it's required. The problem is that such implementation turned to be first
> unscalable (supports a platform with only single eDMA available since a
> base address statically preserved) and second needlessly overcomplicated
> (it loops over all Rd/Wr context addresses and re-calculates the viewport
> base address on each DebugFS node access). The algorithm can be greatly
> simplified just by adding the channel ID and it's direction fields in the
> eDMA DebugFS node descriptor. These new parameters can be used to find a
> CSR offset within the corresponding channel registers space. The DW eDMA
> DebugFS node getter afterwards will also use them in order to activate the
> respective context CSRs viewport before reading data from the specified
> register. In case of the unrolled version of the CSRs mapping there won't
> be any spin-lock taken/released, no viewport activation as before this
> modification.
> 
> Note this modification fixes the REGISTER() macros using an externally
> defined local variable. The same problem with the rest of the macro will
> be fixed in the next commit.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 84 +++++++++++-------------
>  1 file changed, 38 insertions(+), 46 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> index 7eb0147912fa..b34a68964232 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> @@ -15,9 +15,27 @@
>  
>  #define REGS_ADDR(name) \
>  	((void __iomem *)&regs->name)
> +
> +#define REGS_CH_ADDR(name, _dir, _ch)						\
> +	({									\
> +		struct dw_edma_v0_ch_regs __iomem *__ch_regs;			\
> +										\
> +		if ((dw)->chip->mf == EDMA_MF_EDMA_LEGACY)			\
> +			__ch_regs = &regs->type.legacy.ch;			\
> +		else if (_dir == EDMA_DIR_READ)					\
> +			__ch_regs = &regs->type.unroll.ch[_ch].rd;		\
> +		else								\
> +			__ch_regs = &regs->type.unroll.ch[_ch].wr;		\
> +										\
> +		(void __iomem *)&__ch_regs->name;				\
> +	})
> +
>  #define REGISTER(name) \
>  	{ #name, REGS_ADDR(name) }
>  
> +#define CTX_REGISTER(name, dir, ch) \
> +	{ #name, REGS_CH_ADDR(name, dir, ch), dir, ch }

What is the need of "dir, ch" at the end?

> +
>  #define WR_REGISTER(name) \
>  	{ #name, REGS_ADDR(wr_##name) }
>  #define RD_REGISTER(name) \
> @@ -41,14 +59,11 @@
>  static struct dw_edma				*dw;
>  static struct dw_edma_v0_regs			__iomem *regs;
>  
> -static struct {
> -	void					__iomem *start;
> -	void					__iomem *end;
> -} lim[2][EDMA_V0_MAX_NR_CH];
> -
>  struct dw_edma_debugfs_entry {
>  	const char				*name;
>  	void __iomem				*reg;
> +	enum dw_edma_dir			dir;
> +	u16					ch;
>  };
>  
>  static int dw_edma_debugfs_u32_get(void *data, u64 *val)
> @@ -58,33 +73,16 @@ static int dw_edma_debugfs_u32_get(void *data, u64 *val)
>  
>  	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;
>  		unsigned long flags;
> -		u16 ch;
> -
> -		for (ch = 0; ch < dw->wr_ch_cnt; ch++)
> -			if (lim[0][ch].start >= reg && reg < lim[0][ch].end) {
> -				ptr += (reg - lim[0][ch].start);
> -				goto legacy_sel_wr;
> -			}
> -
> -		for (ch = 0; ch < dw->rd_ch_cnt; ch++)
> -			if (lim[1][ch].start >= reg && reg < lim[1][ch].end) {
> -				ptr += (reg - lim[1][ch].start);
> -				goto legacy_sel_rd;
> -			}
> -
> -		return 0;
> -legacy_sel_rd:
> -		viewport_sel = BIT(31);
> -legacy_sel_wr:
> -		viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
> +		u32 viewport_sel;
> +
> +		viewport_sel = entry->dir == EDMA_DIR_READ ? BIT(31) : 0;
> +		viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, entry->ch);
>  
>  		raw_spin_lock_irqsave(&dw->lock, flags);
>  
>  		writel(viewport_sel, &regs->type.legacy.viewport_sel);
> -		*val = readl(ptr);
> +		*val = readl(reg);
>  
>  		raw_spin_unlock_irqrestore(&dw->lock, flags);
>  	} else {
> @@ -114,19 +112,19 @@ static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry ini[],
>  	}
>  }
>  
> -static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs __iomem *regs,
> +static void dw_edma_debugfs_regs_ch(enum dw_edma_dir edma_dir, u16 ch,
>  				    struct dentry *dir)

Using "dir" for directory would be confusing since it could also refer
direction. I'd suggest to use "dentry".

Thanks,
Mani

>  {
> -	const struct dw_edma_debugfs_entry debugfs_regs[] = {
> -		REGISTER(ch_control1),
> -		REGISTER(ch_control2),
> -		REGISTER(transfer_size),
> -		REGISTER(sar.lsb),
> -		REGISTER(sar.msb),
> -		REGISTER(dar.lsb),
> -		REGISTER(dar.msb),
> -		REGISTER(llp.lsb),
> -		REGISTER(llp.msb),
> +	struct dw_edma_debugfs_entry debugfs_regs[] = {
> +		CTX_REGISTER(ch_control1, edma_dir, ch),
> +		CTX_REGISTER(ch_control2, edma_dir, ch),
> +		CTX_REGISTER(transfer_size, edma_dir, ch),
> +		CTX_REGISTER(sar.lsb, edma_dir, ch),
> +		CTX_REGISTER(sar.msb, edma_dir, ch),
> +		CTX_REGISTER(dar.lsb, edma_dir, ch),
> +		CTX_REGISTER(dar.msb, edma_dir, ch),
> +		CTX_REGISTER(llp.lsb, edma_dir, ch),
> +		CTX_REGISTER(llp.msb, edma_dir, ch),
>  	};
>  	int nr_entries;
>  
> @@ -191,10 +189,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
>  
>  		ch_dir = debugfs_create_dir(name, regs_dir);
>  
> -		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].wr, ch_dir);
> -
> -		lim[0][i].start = &regs->type.unroll.ch[i].wr;
> -		lim[0][i].end = &regs->type.unroll.ch[i].padding_1[0];
> +		dw_edma_debugfs_regs_ch(EDMA_DIR_WRITE, i, ch_dir);
>  	}
>  }
>  
> @@ -256,10 +251,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
>  
>  		ch_dir = debugfs_create_dir(name, regs_dir);
>  
> -		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].rd, ch_dir);
> -
> -		lim[1][i].start = &regs->type.unroll.ch[i].rd;
> -		lim[1][i].end = &regs->type.unroll.ch[i].padding_2[0];
> +		dw_edma_debugfs_regs_ch(EDMA_DIR_READ, i, ch_dir);
>  	}
>  }
>  
> -- 
> 2.35.1
> 

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

* Re: [PATCH 16/25] dmaengine: dw-edma: Simplify the DebugFS context CSRs init procedure
  2022-03-25  6:27   ` Manivannan Sadhasivam
@ 2022-03-25  6:31     ` Manivannan Sadhasivam
  2022-04-18  8:23     ` Serge Semin
  1 sibling, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-25  6:31 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Fri, Mar 25, 2022 at 11:57:16AM +0530, Manivannan Sadhasivam wrote:
> On Thu, Mar 24, 2022 at 04:48:27AM +0300, Serge Semin wrote:
> > DW eDMA v4.70a and older have the read and write channels context CSRs
> > indirectly accessible. It means the CSRs like Channel Control, Xfer size,
> > SAR, DAR and LLP address are accessed over at a fixed MMIO address, but
> > their reference to the corresponding channel is determined by the Viewport
> > CSR. In order to have a coherent access to these registers the CSR IOs are
> > supposed to be protected with a spin-lock. DW eDMA v4.80a and newer
> > normally have unrolled Read/Write channel context registers. That is all
> > CSRs denoted before are directly mapped in the controller MMIO space.
> > 
> > Since both normal and viewport-based registers are exposed via the DebugFS
> > nodes, the original code author decided to implement an algorithm based on
> > the unrolled CSRs mapping with the viewport addresses recalculation if
> > it's required. The problem is that such implementation turned to be first
> > unscalable (supports a platform with only single eDMA available since a
> > base address statically preserved) and second needlessly overcomplicated
> > (it loops over all Rd/Wr context addresses and re-calculates the viewport
> > base address on each DebugFS node access). The algorithm can be greatly
> > simplified just by adding the channel ID and it's direction fields in the
> > eDMA DebugFS node descriptor. These new parameters can be used to find a
> > CSR offset within the corresponding channel registers space. The DW eDMA
> > DebugFS node getter afterwards will also use them in order to activate the
> > respective context CSRs viewport before reading data from the specified
> > register. In case of the unrolled version of the CSRs mapping there won't
> > be any spin-lock taken/released, no viewport activation as before this
> > modification.
> > 
> > Note this modification fixes the REGISTER() macros using an externally
> > defined local variable. The same problem with the rest of the macro will
> > be fixed in the next commit.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 84 +++++++++++-------------
> >  1 file changed, 38 insertions(+), 46 deletions(-)
> > 
> > diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > index 7eb0147912fa..b34a68964232 100644
> > --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > @@ -15,9 +15,27 @@
> >  
> >  #define REGS_ADDR(name) \
> >  	((void __iomem *)&regs->name)
> > +
> > +#define REGS_CH_ADDR(name, _dir, _ch)						\
> > +	({									\
> > +		struct dw_edma_v0_ch_regs __iomem *__ch_regs;			\
> > +										\
> > +		if ((dw)->chip->mf == EDMA_MF_EDMA_LEGACY)			\
> > +			__ch_regs = &regs->type.legacy.ch;			\
> > +		else if (_dir == EDMA_DIR_READ)					\
> > +			__ch_regs = &regs->type.unroll.ch[_ch].rd;		\
> > +		else								\
> > +			__ch_regs = &regs->type.unroll.ch[_ch].wr;		\
> > +										\
> > +		(void __iomem *)&__ch_regs->name;				\
> > +	})
> > +
> >  #define REGISTER(name) \
> >  	{ #name, REGS_ADDR(name) }
> >  
> > +#define CTX_REGISTER(name, dir, ch) \
> > +	{ #name, REGS_CH_ADDR(name, dir, ch), dir, ch }
> 
> What is the need of "dir, ch" at the end?
> 

Ignore this comment. I failed to notice that your addition.

Thanks,
Mani

> > +
> >  #define WR_REGISTER(name) \
> >  	{ #name, REGS_ADDR(wr_##name) }
> >  #define RD_REGISTER(name) \
> > @@ -41,14 +59,11 @@
> >  static struct dw_edma				*dw;
> >  static struct dw_edma_v0_regs			__iomem *regs;
> >  
> > -static struct {
> > -	void					__iomem *start;
> > -	void					__iomem *end;
> > -} lim[2][EDMA_V0_MAX_NR_CH];
> > -
> >  struct dw_edma_debugfs_entry {
> >  	const char				*name;
> >  	void __iomem				*reg;
> > +	enum dw_edma_dir			dir;
> > +	u16					ch;
> >  };
> >  
> >  static int dw_edma_debugfs_u32_get(void *data, u64 *val)
> > @@ -58,33 +73,16 @@ static int dw_edma_debugfs_u32_get(void *data, u64 *val)
> >  
> >  	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;
> >  		unsigned long flags;
> > -		u16 ch;
> > -
> > -		for (ch = 0; ch < dw->wr_ch_cnt; ch++)
> > -			if (lim[0][ch].start >= reg && reg < lim[0][ch].end) {
> > -				ptr += (reg - lim[0][ch].start);
> > -				goto legacy_sel_wr;
> > -			}
> > -
> > -		for (ch = 0; ch < dw->rd_ch_cnt; ch++)
> > -			if (lim[1][ch].start >= reg && reg < lim[1][ch].end) {
> > -				ptr += (reg - lim[1][ch].start);
> > -				goto legacy_sel_rd;
> > -			}
> > -
> > -		return 0;
> > -legacy_sel_rd:
> > -		viewport_sel = BIT(31);
> > -legacy_sel_wr:
> > -		viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
> > +		u32 viewport_sel;
> > +
> > +		viewport_sel = entry->dir == EDMA_DIR_READ ? BIT(31) : 0;
> > +		viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, entry->ch);
> >  
> >  		raw_spin_lock_irqsave(&dw->lock, flags);
> >  
> >  		writel(viewport_sel, &regs->type.legacy.viewport_sel);
> > -		*val = readl(ptr);
> > +		*val = readl(reg);
> >  
> >  		raw_spin_unlock_irqrestore(&dw->lock, flags);
> >  	} else {
> > @@ -114,19 +112,19 @@ static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry ini[],
> >  	}
> >  }
> >  
> > -static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs __iomem *regs,
> > +static void dw_edma_debugfs_regs_ch(enum dw_edma_dir edma_dir, u16 ch,
> >  				    struct dentry *dir)
> 
> Using "dir" for directory would be confusing since it could also refer
> direction. I'd suggest to use "dentry".
> 
> Thanks,
> Mani
> 
> >  {
> > -	const struct dw_edma_debugfs_entry debugfs_regs[] = {
> > -		REGISTER(ch_control1),
> > -		REGISTER(ch_control2),
> > -		REGISTER(transfer_size),
> > -		REGISTER(sar.lsb),
> > -		REGISTER(sar.msb),
> > -		REGISTER(dar.lsb),
> > -		REGISTER(dar.msb),
> > -		REGISTER(llp.lsb),
> > -		REGISTER(llp.msb),
> > +	struct dw_edma_debugfs_entry debugfs_regs[] = {
> > +		CTX_REGISTER(ch_control1, edma_dir, ch),
> > +		CTX_REGISTER(ch_control2, edma_dir, ch),
> > +		CTX_REGISTER(transfer_size, edma_dir, ch),
> > +		CTX_REGISTER(sar.lsb, edma_dir, ch),
> > +		CTX_REGISTER(sar.msb, edma_dir, ch),
> > +		CTX_REGISTER(dar.lsb, edma_dir, ch),
> > +		CTX_REGISTER(dar.msb, edma_dir, ch),
> > +		CTX_REGISTER(llp.lsb, edma_dir, ch),
> > +		CTX_REGISTER(llp.msb, edma_dir, ch),
> >  	};
> >  	int nr_entries;
> >  
> > @@ -191,10 +189,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
> >  
> >  		ch_dir = debugfs_create_dir(name, regs_dir);
> >  
> > -		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].wr, ch_dir);
> > -
> > -		lim[0][i].start = &regs->type.unroll.ch[i].wr;
> > -		lim[0][i].end = &regs->type.unroll.ch[i].padding_1[0];
> > +		dw_edma_debugfs_regs_ch(EDMA_DIR_WRITE, i, ch_dir);
> >  	}
> >  }
> >  
> > @@ -256,10 +251,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
> >  
> >  		ch_dir = debugfs_create_dir(name, regs_dir);
> >  
> > -		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].rd, ch_dir);
> > -
> > -		lim[1][i].start = &regs->type.unroll.ch[i].rd;
> > -		lim[1][i].end = &regs->type.unroll.ch[i].padding_2[0];
> > +		dw_edma_debugfs_regs_ch(EDMA_DIR_READ, i, ch_dir);
> >  	}
> >  }
> >  
> > -- 
> > 2.35.1
> > 

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

* Re: [PATCH 17/25] dmaengine: dw-edma: Move eDMA data pointer to DebugFS node descriptor
  2022-03-24  1:48 ` [PATCH 17/25] dmaengine: dw-edma: Move eDMA data pointer to DebugFS node descriptor Serge Semin
@ 2022-03-25  6:35   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-25  6:35 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:28AM +0300, Serge Semin wrote:
> The last thing that really stops the DebugFS part of the eDMA driver from
> supporting the multi-eDMA platform in is keeping the eDMA private data
> pointer in the static area of the DebugFS module. Since the DebugFS node
> descriptors are now kz-allocated we can freely move that pointer to being
> preserved in the descriptors. After the DebugFS initialization procedure
> that pointer will be used in the DebugFS files getter to access the common
> CSRs space and the context CSRs spin-lock. So the main part of this change
> is connected with the DebugFS nodes descriptors initialization macros,
> which aside with already defined prototypes now require to have the DW
> eDMA private data pointer passed.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

Thanks,
Mani

> ---
>  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 240 +++++++++++------------
>  1 file changed, 118 insertions(+), 122 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> index b34a68964232..353269a3680b 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> @@ -13,53 +13,55 @@
>  #include "dw-edma-v0-regs.h"
>  #include "dw-edma-core.h"
>  
> -#define REGS_ADDR(name) \
> -	((void __iomem *)&regs->name)
> +#define REGS_ADDR(dw, name)							\
> +	({									\
> +		struct dw_edma_v0_regs __iomem *__regs = (dw)->chip->reg_base;	\
> +										\
> +		(void __iomem *)&__regs->name;					\
> +	})
>  
> -#define REGS_CH_ADDR(name, _dir, _ch)						\
> +#define REGS_CH_ADDR(dw, name, _dir, _ch)					\
>  	({									\
>  		struct dw_edma_v0_ch_regs __iomem *__ch_regs;			\
>  										\
>  		if ((dw)->chip->mf == EDMA_MF_EDMA_LEGACY)			\
> -			__ch_regs = &regs->type.legacy.ch;			\
> +			__ch_regs = REGS_ADDR(dw, type.legacy.ch);		\
>  		else if (_dir == EDMA_DIR_READ)					\
> -			__ch_regs = &regs->type.unroll.ch[_ch].rd;		\
> +			__ch_regs = REGS_ADDR(dw, type.unroll.ch[_ch].rd);	\
>  		else								\
> -			__ch_regs = &regs->type.unroll.ch[_ch].wr;		\
> +			__ch_regs = REGS_ADDR(dw, type.unroll.ch[_ch].wr);	\
>  										\
>  		(void __iomem *)&__ch_regs->name;				\
>  	})
>  
> -#define REGISTER(name) \
> -	{ #name, REGS_ADDR(name) }
> +#define REGISTER(dw, name) \
> +	{ dw, #name, REGS_ADDR(dw, name) }
>  
> -#define CTX_REGISTER(name, dir, ch) \
> -	{ #name, REGS_CH_ADDR(name, dir, ch), dir, ch }
> +#define CTX_REGISTER(dw, name, dir, ch) \
> +	{ dw, #name, REGS_CH_ADDR(dw, name, dir, ch), dir, ch }
>  
> -#define WR_REGISTER(name) \
> -	{ #name, REGS_ADDR(wr_##name) }
> -#define RD_REGISTER(name) \
> -	{ #name, REGS_ADDR(rd_##name) }
> +#define WR_REGISTER(dw, name) \
> +	{ dw, #name, REGS_ADDR(dw, wr_##name) }
> +#define RD_REGISTER(dw, name) \
> +	{ dw, #name, REGS_ADDR(dw, rd_##name) }
>  
> -#define WR_REGISTER_LEGACY(name) \
> -	{ #name, REGS_ADDR(type.legacy.wr_##name) }
> +#define WR_REGISTER_LEGACY(dw, name) \
> +	{ dw, #name, REGS_ADDR(dw, type.legacy.wr_##name) }
>  #define RD_REGISTER_LEGACY(name) \
> -	{ #name, REGS_ADDR(type.legacy.rd_##name) }
> +	{ dw, #name, REGS_ADDR(dw, type.legacy.rd_##name) }
>  
> -#define WR_REGISTER_UNROLL(name) \
> -	{ #name, REGS_ADDR(type.unroll.wr_##name) }
> -#define RD_REGISTER_UNROLL(name) \
> -	{ #name, REGS_ADDR(type.unroll.rd_##name) }
> +#define WR_REGISTER_UNROLL(dw, name) \
> +	{ dw, #name, REGS_ADDR(dw, type.unroll.wr_##name) }
> +#define RD_REGISTER_UNROLL(dw, name) \
> +	{ dw, #name, REGS_ADDR(dw, type.unroll.rd_##name) }
>  
>  #define WRITE_STR				"write"
>  #define READ_STR				"read"
>  #define CHANNEL_STR				"channel"
>  #define REGISTERS_STR				"registers"
>  
> -static struct dw_edma				*dw;
> -static struct dw_edma_v0_regs			__iomem *regs;
> -
>  struct dw_edma_debugfs_entry {
> +	struct dw_edma				*dw;
>  	const char				*name;
>  	void __iomem				*reg;
>  	enum dw_edma_dir			dir;
> @@ -69,10 +71,11 @@ struct dw_edma_debugfs_entry {
>  static int dw_edma_debugfs_u32_get(void *data, u64 *val)
>  {
>  	struct dw_edma_debugfs_entry __iomem *entry = data;
> +	struct dw_edma *dw = entry->dw;
>  	void __iomem *reg = entry->reg;
>  
>  	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
> -	    reg >= (void __iomem *)&regs->type.legacy.ch) {
> +	    reg >= REGS_ADDR(dw, type.legacy.ch)) {
>  		unsigned long flags;
>  		u32 viewport_sel;
>  
> @@ -81,7 +84,7 @@ static int dw_edma_debugfs_u32_get(void *data, u64 *val)
>  
>  		raw_spin_lock_irqsave(&dw->lock, flags);
>  
> -		writel(viewport_sel, &regs->type.legacy.viewport_sel);
> +		writel(viewport_sel, REGS_ADDR(dw, type.legacy.viewport_sel));
>  		*val = readl(reg);
>  
>  		raw_spin_unlock_irqrestore(&dw->lock, flags);
> @@ -93,7 +96,8 @@ static int dw_edma_debugfs_u32_get(void *data, u64 *val)
>  }
>  DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");
>  
> -static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry ini[],
> +static void dw_edma_debugfs_create_x32(struct dw_edma *dw,
> +				       const struct dw_edma_debugfs_entry ini[],
>  				       int nr_entries, struct dentry *dir)
>  {
>  	struct dw_edma_debugfs_entry *entries;
> @@ -112,62 +116,62 @@ static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry ini[],
>  	}
>  }
>  
> -static void dw_edma_debugfs_regs_ch(enum dw_edma_dir edma_dir, u16 ch,
> -				    struct dentry *dir)
> +static void dw_edma_debugfs_regs_ch(struct dw_edma *dw, enum dw_edma_dir edma_dir,
> +				    u16 ch, struct dentry *dir)
>  {
>  	struct dw_edma_debugfs_entry debugfs_regs[] = {
> -		CTX_REGISTER(ch_control1, edma_dir, ch),
> -		CTX_REGISTER(ch_control2, edma_dir, ch),
> -		CTX_REGISTER(transfer_size, edma_dir, ch),
> -		CTX_REGISTER(sar.lsb, edma_dir, ch),
> -		CTX_REGISTER(sar.msb, edma_dir, ch),
> -		CTX_REGISTER(dar.lsb, edma_dir, ch),
> -		CTX_REGISTER(dar.msb, edma_dir, ch),
> -		CTX_REGISTER(llp.lsb, edma_dir, ch),
> -		CTX_REGISTER(llp.msb, edma_dir, ch),
> +		CTX_REGISTER(dw, ch_control1, edma_dir, ch),
> +		CTX_REGISTER(dw, ch_control2, edma_dir, ch),
> +		CTX_REGISTER(dw, transfer_size, edma_dir, ch),
> +		CTX_REGISTER(dw, sar.lsb, edma_dir, ch),
> +		CTX_REGISTER(dw, sar.msb, edma_dir, ch),
> +		CTX_REGISTER(dw, dar.lsb, edma_dir, ch),
> +		CTX_REGISTER(dw, dar.msb, edma_dir, ch),
> +		CTX_REGISTER(dw, llp.lsb, edma_dir, ch),
> +		CTX_REGISTER(dw, llp.msb, edma_dir, ch),
>  	};
>  	int nr_entries;
>  
>  	nr_entries = ARRAY_SIZE(debugfs_regs);
> -	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, dir);
> +	dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, dir);
>  }
>  
> -static void dw_edma_debugfs_regs_wr(struct dentry *dir)
> +static void dw_edma_debugfs_regs_wr(struct dw_edma *dw, struct dentry *dir)
>  {
>  	const struct dw_edma_debugfs_entry debugfs_regs[] = {
>  		/* eDMA global registers */
> -		WR_REGISTER(engine_en),
> -		WR_REGISTER(doorbell),
> -		WR_REGISTER(ch_arb_weight.lsb),
> -		WR_REGISTER(ch_arb_weight.msb),
> +		WR_REGISTER(dw, engine_en),
> +		WR_REGISTER(dw, doorbell),
> +		WR_REGISTER(dw, ch_arb_weight.lsb),
> +		WR_REGISTER(dw, ch_arb_weight.msb),
>  		/* eDMA interrupts registers */
> -		WR_REGISTER(int_status),
> -		WR_REGISTER(int_mask),
> -		WR_REGISTER(int_clear),
> -		WR_REGISTER(err_status),
> -		WR_REGISTER(done_imwr.lsb),
> -		WR_REGISTER(done_imwr.msb),
> -		WR_REGISTER(abort_imwr.lsb),
> -		WR_REGISTER(abort_imwr.msb),
> -		WR_REGISTER(ch01_imwr_data),
> -		WR_REGISTER(ch23_imwr_data),
> -		WR_REGISTER(ch45_imwr_data),
> -		WR_REGISTER(ch67_imwr_data),
> -		WR_REGISTER(linked_list_err_en),
> +		WR_REGISTER(dw, int_status),
> +		WR_REGISTER(dw, int_mask),
> +		WR_REGISTER(dw, int_clear),
> +		WR_REGISTER(dw, err_status),
> +		WR_REGISTER(dw, done_imwr.lsb),
> +		WR_REGISTER(dw, done_imwr.msb),
> +		WR_REGISTER(dw, abort_imwr.lsb),
> +		WR_REGISTER(dw, abort_imwr.msb),
> +		WR_REGISTER(dw, ch01_imwr_data),
> +		WR_REGISTER(dw, ch23_imwr_data),
> +		WR_REGISTER(dw, ch45_imwr_data),
> +		WR_REGISTER(dw, ch67_imwr_data),
> +		WR_REGISTER(dw, linked_list_err_en),
>  	};
>  	const struct dw_edma_debugfs_entry debugfs_unroll_regs[] = {
>  		/* eDMA channel context grouping */
> -		WR_REGISTER_UNROLL(engine_chgroup),
> -		WR_REGISTER_UNROLL(engine_hshake_cnt.lsb),
> -		WR_REGISTER_UNROLL(engine_hshake_cnt.msb),
> -		WR_REGISTER_UNROLL(ch0_pwr_en),
> -		WR_REGISTER_UNROLL(ch1_pwr_en),
> -		WR_REGISTER_UNROLL(ch2_pwr_en),
> -		WR_REGISTER_UNROLL(ch3_pwr_en),
> -		WR_REGISTER_UNROLL(ch4_pwr_en),
> -		WR_REGISTER_UNROLL(ch5_pwr_en),
> -		WR_REGISTER_UNROLL(ch6_pwr_en),
> -		WR_REGISTER_UNROLL(ch7_pwr_en),
> +		WR_REGISTER_UNROLL(dw, engine_chgroup),
> +		WR_REGISTER_UNROLL(dw, engine_hshake_cnt.lsb),
> +		WR_REGISTER_UNROLL(dw, engine_hshake_cnt.msb),
> +		WR_REGISTER_UNROLL(dw, ch0_pwr_en),
> +		WR_REGISTER_UNROLL(dw, ch1_pwr_en),
> +		WR_REGISTER_UNROLL(dw, ch2_pwr_en),
> +		WR_REGISTER_UNROLL(dw, ch3_pwr_en),
> +		WR_REGISTER_UNROLL(dw, ch4_pwr_en),
> +		WR_REGISTER_UNROLL(dw, ch5_pwr_en),
> +		WR_REGISTER_UNROLL(dw, ch6_pwr_en),
> +		WR_REGISTER_UNROLL(dw, ch7_pwr_en),
>  	};
>  	struct dentry *regs_dir, *ch_dir;
>  	int nr_entries, i;
> @@ -176,11 +180,11 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
>  	regs_dir = debugfs_create_dir(WRITE_STR, dir);
>  
>  	nr_entries = ARRAY_SIZE(debugfs_regs);
> -	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
> +	dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dir);
>  
>  	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,
> +		dw_edma_debugfs_create_x32(dw, debugfs_unroll_regs, nr_entries,
>  					   regs_dir);
>  	}
>  
> @@ -189,47 +193,47 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
>  
>  		ch_dir = debugfs_create_dir(name, regs_dir);
>  
> -		dw_edma_debugfs_regs_ch(EDMA_DIR_WRITE, i, ch_dir);
> +		dw_edma_debugfs_regs_ch(dw, EDMA_DIR_WRITE, i, ch_dir);
>  	}
>  }
>  
> -static void dw_edma_debugfs_regs_rd(struct dentry *dir)
> +static void dw_edma_debugfs_regs_rd(struct dw_edma *dw, struct dentry *dir)
>  {
>  	const struct dw_edma_debugfs_entry debugfs_regs[] = {
>  		/* eDMA global registers */
> -		RD_REGISTER(engine_en),
> -		RD_REGISTER(doorbell),
> -		RD_REGISTER(ch_arb_weight.lsb),
> -		RD_REGISTER(ch_arb_weight.msb),
> +		RD_REGISTER(dw, engine_en),
> +		RD_REGISTER(dw, doorbell),
> +		RD_REGISTER(dw, ch_arb_weight.lsb),
> +		RD_REGISTER(dw, ch_arb_weight.msb),
>  		/* eDMA interrupts registers */
> -		RD_REGISTER(int_status),
> -		RD_REGISTER(int_mask),
> -		RD_REGISTER(int_clear),
> -		RD_REGISTER(err_status.lsb),
> -		RD_REGISTER(err_status.msb),
> -		RD_REGISTER(linked_list_err_en),
> -		RD_REGISTER(done_imwr.lsb),
> -		RD_REGISTER(done_imwr.msb),
> -		RD_REGISTER(abort_imwr.lsb),
> -		RD_REGISTER(abort_imwr.msb),
> -		RD_REGISTER(ch01_imwr_data),
> -		RD_REGISTER(ch23_imwr_data),
> -		RD_REGISTER(ch45_imwr_data),
> -		RD_REGISTER(ch67_imwr_data),
> +		RD_REGISTER(dw, int_status),
> +		RD_REGISTER(dw, int_mask),
> +		RD_REGISTER(dw, int_clear),
> +		RD_REGISTER(dw, err_status.lsb),
> +		RD_REGISTER(dw, err_status.msb),
> +		RD_REGISTER(dw, linked_list_err_en),
> +		RD_REGISTER(dw, done_imwr.lsb),
> +		RD_REGISTER(dw, done_imwr.msb),
> +		RD_REGISTER(dw, abort_imwr.lsb),
> +		RD_REGISTER(dw, abort_imwr.msb),
> +		RD_REGISTER(dw, ch01_imwr_data),
> +		RD_REGISTER(dw, ch23_imwr_data),
> +		RD_REGISTER(dw, ch45_imwr_data),
> +		RD_REGISTER(dw, ch67_imwr_data),
>  	};
>  	const struct dw_edma_debugfs_entry debugfs_unroll_regs[] = {
>  		/* eDMA channel context grouping */
> -		RD_REGISTER_UNROLL(engine_chgroup),
> -		RD_REGISTER_UNROLL(engine_hshake_cnt.lsb),
> -		RD_REGISTER_UNROLL(engine_hshake_cnt.msb),
> -		RD_REGISTER_UNROLL(ch0_pwr_en),
> -		RD_REGISTER_UNROLL(ch1_pwr_en),
> -		RD_REGISTER_UNROLL(ch2_pwr_en),
> -		RD_REGISTER_UNROLL(ch3_pwr_en),
> -		RD_REGISTER_UNROLL(ch4_pwr_en),
> -		RD_REGISTER_UNROLL(ch5_pwr_en),
> -		RD_REGISTER_UNROLL(ch6_pwr_en),
> -		RD_REGISTER_UNROLL(ch7_pwr_en),
> +		RD_REGISTER_UNROLL(dw, engine_chgroup),
> +		RD_REGISTER_UNROLL(dw, engine_hshake_cnt.lsb),
> +		RD_REGISTER_UNROLL(dw, engine_hshake_cnt.msb),
> +		RD_REGISTER_UNROLL(dw, ch0_pwr_en),
> +		RD_REGISTER_UNROLL(dw, ch1_pwr_en),
> +		RD_REGISTER_UNROLL(dw, ch2_pwr_en),
> +		RD_REGISTER_UNROLL(dw, ch3_pwr_en),
> +		RD_REGISTER_UNROLL(dw, ch4_pwr_en),
> +		RD_REGISTER_UNROLL(dw, ch5_pwr_en),
> +		RD_REGISTER_UNROLL(dw, ch6_pwr_en),
> +		RD_REGISTER_UNROLL(dw, ch7_pwr_en),
>  	};
>  	struct dentry *regs_dir, *ch_dir;
>  	int nr_entries, i;
> @@ -238,11 +242,11 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
>  	regs_dir = debugfs_create_dir(READ_STR, dir);
>  
>  	nr_entries = ARRAY_SIZE(debugfs_regs);
> -	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
> +	dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dir);
>  
>  	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,
> +		dw_edma_debugfs_create_x32(dw, debugfs_unroll_regs, nr_entries,
>  					   regs_dir);
>  	}
>  
> @@ -251,15 +255,15 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
>  
>  		ch_dir = debugfs_create_dir(name, regs_dir);
>  
> -		dw_edma_debugfs_regs_ch(EDMA_DIR_READ, i, ch_dir);
> +		dw_edma_debugfs_regs_ch(dw, EDMA_DIR_READ, i, ch_dir);
>  	}
>  }
>  
> -static void dw_edma_debugfs_regs(void)
> +static void dw_edma_debugfs_regs(struct dw_edma *dw)
>  {
>  	const struct dw_edma_debugfs_entry debugfs_regs[] = {
> -		REGISTER(ctrl_data_arb_prior),
> -		REGISTER(ctrl),
> +		REGISTER(dw, ctrl_data_arb_prior),
> +		REGISTER(dw, ctrl),
>  	};
>  	struct dentry *regs_dir;
>  	int nr_entries;
> @@ -267,23 +271,17 @@ static void dw_edma_debugfs_regs(void)
>  	regs_dir = debugfs_create_dir(REGISTERS_STR, dw->debugfs);
>  
>  	nr_entries = ARRAY_SIZE(debugfs_regs);
> -	dw_edma_debugfs_create_x32(debugfs_regs, nr_entries, regs_dir);
> +	dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dir);
>  
> -	dw_edma_debugfs_regs_wr(regs_dir);
> -	dw_edma_debugfs_regs_rd(regs_dir);
> +	dw_edma_debugfs_regs_wr(dw, regs_dir);
> +	dw_edma_debugfs_regs_rd(dw, regs_dir);
>  }
>  
>  void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
>  {
> -	if (!debugfs_initialized())
> -		return;
> -
> -	dw = chip->dw;
> -	if (!dw)
> -		return;
> +	struct dw_edma *dw = chip->dw;
>  
> -	regs = dw->chip->reg_base;
> -	if (!regs)
> +	if (!debugfs_initialized())
>  		return;
>  
>  	dw->debugfs = debugfs_create_dir(dw->name, NULL);
> @@ -292,14 +290,12 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
>  	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);
>  
> -	dw_edma_debugfs_regs();
> +	dw_edma_debugfs_regs(dw);
>  }
>  
>  void dw_edma_v0_debugfs_off(struct dw_edma_chip *chip)
>  {
> -	dw = chip->dw;
> -	if (!dw)
> -		return;
> +	struct dw_edma *dw = chip->dw;
>  
>  	debugfs_remove_recursive(dw->debugfs);
>  	dw->debugfs = NULL;
> -- 
> 2.35.1
> 

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

* Re: [PATCH 15/25] dmaengine: dw-edma: Convert DebugFS descs to being kz-allocated
  2022-03-25  6:03   ` Manivannan Sadhasivam
@ 2022-03-25  6:42     ` Manivannan Sadhasivam
  2022-04-18  7:17     ` Serge Semin
  1 sibling, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-25  6:42 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Fri, Mar 25, 2022 at 11:33:57AM +0530, Manivannan Sadhasivam wrote:
> On Thu, Mar 24, 2022 at 04:48:26AM +0300, Serge Semin wrote:
> > Currently all the DW eDMA DebugFS nodes descriptors are allocated on
> > stack, while the DW eDMA driver private data and CSR limits are statically
> > preserved. Such design won't work for the multi-eDMA platforms.
> 
> Can you please explain why?
> 
> > As a
> > preparation to adding the multi-eDMA system setups support we need to have
> > each DebugFS node separately allocated and described. Afterwards we'll put
> > an addition info there like Read/Write channel flag, channel ID, DW eDMA
> > private data reference.
> > 
> > Note this conversion is mainly required due to having the legacy DW eDMA
> > controllers with indirect Read/Write channels context CSRs access. If we
> > didn't need to have a synchronized access to these registers the DebugFS
> > code of the driver would have been much simpler.
> > 
> 
> I fail to understand how this change is beneficial or the exact issue.
> 

I think I get the reasoning after going through the successive patches.

Thanks,
Mani

> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 15 ++++++++++++---
> >  1 file changed, 12 insertions(+), 3 deletions(-)
> > 
> > diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > index afd519d9568b..7eb0147912fa 100644
> > --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > @@ -53,7 +53,8 @@ struct dw_edma_debugfs_entry {
> >  
> >  static int dw_edma_debugfs_u32_get(void *data, u64 *val)
> >  {
> > -	void __iomem *reg = data;
> > +	struct dw_edma_debugfs_entry __iomem *entry = data;
> 
> Why the entry has to be of __iomem?
> 
> Thanks,
> Mani
> 
> > +	void __iomem *reg = entry->reg;
> >  
> >  	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
> >  	    reg >= (void __iomem *)&regs->type.legacy.ch) {
> > @@ -94,14 +95,22 @@ static int dw_edma_debugfs_u32_get(void *data, u64 *val)
> >  }
> >  DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");
> >  
> > -static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry entries[],
> > +static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry ini[],
> >  				       int nr_entries, struct dentry *dir)
> >  {
> > +	struct dw_edma_debugfs_entry *entries;
> >  	int i;
> >  
> > +	entries = devm_kcalloc(dw->chip->dev, nr_entries, sizeof(*entries),
> > +			       GFP_KERNEL);
> > +	if (!entries)
> > +		return;
> > +
> >  	for (i = 0; i < nr_entries; i++) {
> > +		entries[i] = ini[i];
> > +
> >  		debugfs_create_file_unsafe(entries[i].name, 0444, dir,
> > -					   entries[i].reg, &fops_x32);
> > +					   &entries[i], &fops_x32);
> >  	}
> >  }
> >  
> > -- 
> > 2.35.1
> > 

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

* Re: [PATCH 18/25] dmaengine: dw-edma: Join Write/Read channels into a single device
  2022-03-24  1:48 ` [PATCH 18/25] dmaengine: dw-edma: Join Write/Read channels into a single device Serge Semin
@ 2022-03-25  7:34   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-25  7:34 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:29AM +0300, Serge Semin wrote:
> Indeed there is no point in such split up because due to multiple reasons.
> First of all eDMA read and write channels belong to one physical
> controller. Splitting them up illogical. Secondly the channels
> differentiating can be done by means of the filtering and the
> dma_get_slave_caps() method. Finally having these channels handled
> separately not only needlessly complicates the code, but also causes the
> DebugFS error printed to console:
> 
> >> Debugfs: Directory '1f052000.pcie' with parent 'dmaengine' already present!
> 
> So to speak let's join the read/write channels into a single DMA device.
> The client drivers will be able to choose the channel with required
> capability by getting the DMA slave direction setting. It's default value
> is overridden by the dw_edma_device_caps() callback in accordance with the
> channel nature.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

I'm all in for this!

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

Thanks,
Mani

> ---
>  drivers/dma/dw-edma/dw-edma-core.c | 117 +++++++++++++++--------------
>  drivers/dma/dw-edma/dw-edma-core.h |   5 +-
>  2 files changed, 62 insertions(+), 60 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index cefa73412bf7..a391e44da039 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -209,6 +209,24 @@ static void dw_edma_start_transfer(struct dw_edma_chan *chan)
>  	desc->chunks_alloc--;
>  }
>  
> +static void dw_edma_device_caps(struct dma_chan *dchan,
> +				struct dma_slave_caps *caps)
> +{
> +	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
> +
> +	if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
> +		if (chan->dir == EDMA_DIR_READ)
> +			caps->directions = BIT(DMA_DEV_TO_MEM);
> +		else
> +			caps->directions = BIT(DMA_MEM_TO_DEV);
> +	} else {
> +		if (chan->dir == EDMA_DIR_WRITE)
> +			caps->directions = BIT(DMA_DEV_TO_MEM);
> +		else
> +			caps->directions = BIT(DMA_MEM_TO_DEV);
> +	}
> +}
> +
>  static int dw_edma_device_config(struct dma_chan *dchan,
>  				 struct dma_slave_config *config)
>  {
> @@ -723,8 +741,8 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
>  	pm_runtime_put(chan->dw->chip->dev);
>  }
>  
> -static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
> -				 u32 wr_alloc, u32 rd_alloc)
> +static int dw_edma_channel_setup(struct dw_edma_chip *chip, u32 wr_alloc,
> +				 u32 rd_alloc)
>  {
>  	struct dw_edma_region *dt_region;
>  	struct device *dev = chip->dev;
> @@ -732,27 +750,15 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  	struct dw_edma_chan *chan;
>  	struct dw_edma_irq *irq;
>  	struct dma_device *dma;
> -	u32 alloc, off_alloc;
> -	u32 i, j, cnt;
> -	int err = 0;
> +	u32 i, ch_cnt;
>  	u32 pos;
>  
> -	if (write) {
> -		i = 0;
> -		cnt = dw->wr_ch_cnt;
> -		dma = &dw->wr_edma;
> -		alloc = wr_alloc;
> -		off_alloc = 0;
> -	} else {
> -		i = dw->wr_ch_cnt;
> -		cnt = dw->rd_ch_cnt;
> -		dma = &dw->rd_edma;
> -		alloc = rd_alloc;
> -		off_alloc = wr_alloc;
> -	}
> +	ch_cnt = dw->wr_ch_cnt + dw->rd_ch_cnt;
> +	dma = &dw->dma;
>  
>  	INIT_LIST_HEAD(&dma->channels);
> -	for (j = 0; (alloc || chip->nr_irqs == 1) && j < cnt; j++, i++) {
> +
> +	for (i = 0; i < ch_cnt; i++) {
>  		chan = &dw->chan[i];
>  
>  		dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
> @@ -762,52 +768,62 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  		chan->vc.chan.private = dt_region;
>  
>  		chan->dw = dw;
> -		chan->id = j;
> -		chan->dir = write ? EDMA_DIR_WRITE : EDMA_DIR_READ;
> +
> +		if (i < dw->wr_ch_cnt) {
> +			chan->id = i;
> +			chan->dir = EDMA_DIR_WRITE;
> +		} else {
> +			chan->id = i - dw->wr_ch_cnt;
> +			chan->dir = EDMA_DIR_READ;
> +		}
> +
>  		chan->configured = false;
>  		chan->request = EDMA_REQ_NONE;
>  		chan->status = EDMA_ST_IDLE;
>  
> -		if (write)
> -			chan->ll_max = (chip->ll_region_wr[j].sz / EDMA_LL_SZ);
> +		if (chan->dir == EDMA_DIR_WRITE)
> +			chan->ll_max = (chip->ll_region_wr[chan->id].sz / EDMA_LL_SZ);
>  		else
> -			chan->ll_max = (chip->ll_region_rd[j].sz / EDMA_LL_SZ);
> +			chan->ll_max = (chip->ll_region_rd[chan->id].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);
> +			 chan->dir == EDMA_DIR_WRITE ? "write" : "read",
> +			 chan->id, chan->ll_max);
>  
>  		if (chip->nr_irqs == 1)
>  			pos = 0;
> +		else if (chan->dir == EDMA_DIR_WRITE)
> +			pos = chan->id % wr_alloc;
>  		else
> -			pos = off_alloc + (j % alloc);
> +			pos = wr_alloc + chan->id % rd_alloc;
>  
>  		irq = &dw->irq[pos];
>  
> -		if (write)
> -			irq->wr_mask |= BIT(j);
> +		if (chan->dir == EDMA_DIR_WRITE)
> +			irq->wr_mask |= BIT(chan->id);
>  		else
> -			irq->rd_mask |= BIT(j);
> +			irq->rd_mask |= BIT(chan->id);
>  
>  		irq->dw = dw;
>  		memcpy(&chan->msi, &irq->msi, sizeof(chan->msi));
>  
>  		dev_vdbg(dev, "MSI:\t\tChannel %s[%u] addr=0x%.8x%.8x, data=0x%.8x\n",
> -			 write ? "write" : "read", j,
> +			 chan->dir == EDMA_DIR_WRITE  ? "write" : "read", chan->id,
>  			 chan->msi.address_hi, chan->msi.address_lo,
>  			 chan->msi.data);
>  
>  		chan->vc.desc_free = vchan_free_desc;
>  		vchan_init(&chan->vc, dma);
>  
> -		if (write) {
> -			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;
> +		if (chan->dir == EDMA_DIR_WRITE) {
> +			dt_region->paddr = chip->dt_region_wr[chan->id].paddr;
> +			dt_region->vaddr = chip->dt_region_wr[chan->id].vaddr;
> +			dt_region->sz = chip->dt_region_wr[chan->id].sz;
>  		} else {
> -			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;
> +			dt_region->paddr = chip->dt_region_rd[chan->id].paddr;
> +			dt_region->vaddr = chip->dt_region_rd[chan->id].vaddr;
> +			dt_region->sz = chip->dt_region_rd[chan->id].sz;
>  		}
>  
>  		dw_edma_v0_core_device_config(chan);
> @@ -819,7 +835,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  	dma_cap_set(DMA_CYCLIC, dma->cap_mask);
>  	dma_cap_set(DMA_PRIVATE, dma->cap_mask);
>  	dma_cap_set(DMA_INTERLEAVE, dma->cap_mask);
> -	dma->directions = BIT(write ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV);
> +	dma->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
>  	dma->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
>  	dma->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
>  	dma->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
> @@ -828,6 +844,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  	dma->dev = chip->dev;
>  	dma->device_alloc_chan_resources = dw_edma_alloc_chan_resources;
>  	dma->device_free_chan_resources = dw_edma_free_chan_resources;
> +	dma->device_caps = dw_edma_device_caps;
>  	dma->device_config = dw_edma_device_config;
>  	dma->device_pause = dw_edma_device_pause;
>  	dma->device_resume = dw_edma_device_resume;
> @@ -841,9 +858,7 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, bool write,
>  	dma_set_max_seg_size(dma->dev, U32_MAX);
>  
>  	/* Register DMA device */
> -	err = dma_async_device_register(dma);
> -
> -	return err;
> +	return dma_async_device_register(dma);
>  }
>  
>  static inline void dw_edma_dec_irq_alloc(int *nr_irqs, u32 *alloc, u16 cnt)
> @@ -982,13 +997,8 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>  	if (err)
>  		return err;
>  
> -	/* Setup write channels */
> -	err = dw_edma_channel_setup(chip, true, wr_alloc, rd_alloc);
> -	if (err)
> -		goto err_irq_free;
> -
> -	/* Setup read channels */
> -	err = dw_edma_channel_setup(chip, false, wr_alloc, rd_alloc);
> +	/* Setup write/read channels */
> +	err = dw_edma_channel_setup(chip, wr_alloc, rd_alloc);
>  	if (err)
>  		goto err_irq_free;
>  
> @@ -1028,15 +1038,8 @@ int dw_edma_remove(struct dw_edma_chip *chip)
>  	pm_runtime_disable(dev);
>  
>  	/* Deregister eDMA device */
> -	dma_async_device_unregister(&dw->wr_edma);
> -	list_for_each_entry_safe(chan, _chan, &dw->wr_edma.channels,
> -				 vc.chan.device_node) {
> -		tasklet_kill(&chan->vc.task);
> -		list_del(&chan->vc.chan.device_node);
> -	}
> -
> -	dma_async_device_unregister(&dw->rd_edma);
> -	list_for_each_entry_safe(chan, _chan, &dw->rd_edma.channels,
> +	dma_async_device_unregister(&dw->dma);
> +	list_for_each_entry_safe(chan, _chan, &dw->dma.channels,
>  				 vc.chan.device_node) {
>  		tasklet_kill(&chan->vc.task);
>  		list_del(&chan->vc.chan.device_node);
> diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
> index e254c2fc3d9c..ec9f84a857d1 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.h
> +++ b/drivers/dma/dw-edma/dw-edma-core.h
> @@ -98,10 +98,9 @@ struct dw_edma_irq {
>  struct dw_edma {
>  	char				name[20];
>  
> -	struct dma_device		wr_edma;
> -	u16				wr_ch_cnt;
> +	struct dma_device		dma;
>  
> -	struct dma_device		rd_edma;
> +	u16				wr_ch_cnt;
>  	u16				rd_ch_cnt;
>  
>  	struct dw_edma_irq		*irq;
> -- 
> 2.35.1
> 

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

* Re: [PATCH 19/25] dmaengine: dw-edma: Use DMA-engine device DebugFS subdirectory
  2022-03-24  1:48 ` [PATCH 19/25] dmaengine: dw-edma: Use DMA-engine device DebugFS subdirectory Serge Semin
@ 2022-03-25  7:41   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-25  7:41 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:30AM +0300, Serge Semin wrote:
> Since all DW eDMA read and write channels are now installed in a framework
> of a single DMA-engine device, we can freely move all the DW eDMA-specific
> DebugFS nodes into a ready-to-use DMA-engine DebugFS subdirectory. It's
> created during the DMA-device registration and can be found in the
> dma_device.dbg_dev_root field.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

Thanks,
Mani

> ---
>  drivers/dma/dw-edma/dw-edma-core.c       |  3 ---
>  drivers/dma/dw-edma/dw-edma-core.h       |  3 ---
>  drivers/dma/dw-edma/dw-edma-v0-core.c    |  5 -----
>  drivers/dma/dw-edma/dw-edma-v0-core.h    |  1 -
>  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 18 ++++--------------
>  drivers/dma/dw-edma/dw-edma-v0-debugfs.h |  5 -----
>  6 files changed, 4 insertions(+), 31 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index a391e44da039..bc530f0a2468 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -1045,9 +1045,6 @@ int dw_edma_remove(struct dw_edma_chip *chip)
>  		list_del(&chan->vc.chan.device_node);
>  	}
>  
> -	/* Turn debugfs off */
> -	dw_edma_v0_core_debugfs_off(chip);
> -
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(dw_edma_remove);
> diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
> index ec9f84a857d1..980adb079182 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.h
> +++ b/drivers/dma/dw-edma/dw-edma-core.h
> @@ -110,9 +110,6 @@ struct dw_edma {
>  	raw_spinlock_t			lock;		/* Only for legacy */
>  
>  	struct dw_edma_chip             *chip;
> -#ifdef CONFIG_DEBUG_FS
> -	struct dentry			*debugfs;
> -#endif /* CONFIG_DEBUG_FS */
>  };
>  
>  struct dw_edma_sg {
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> index 013d9a9cb991..6b303d5a6b2a 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> @@ -511,8 +511,3 @@ void dw_edma_v0_core_debugfs_on(struct dw_edma_chip *chip)
>  {
>  	dw_edma_v0_debugfs_on(chip);
>  }
> -
> -void dw_edma_v0_core_debugfs_off(struct dw_edma_chip *chip)
> -{
> -	dw_edma_v0_debugfs_off(chip);
> -}
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.h b/drivers/dma/dw-edma/dw-edma-v0-core.h
> index 2afa626b8300..43e01844375a 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-core.h
> +++ b/drivers/dma/dw-edma/dw-edma-v0-core.h
> @@ -23,6 +23,5 @@ 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);
>  /* eDMA debug fs callbacks */
>  void dw_edma_v0_core_debugfs_on(struct dw_edma_chip *chip);
> -void dw_edma_v0_core_debugfs_off(struct dw_edma_chip *chip);
>  
>  #endif /* _DW_EDMA_V0_CORE_H */
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> index 353269a3680b..319a3c790dc4 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> @@ -268,7 +268,7 @@ static void dw_edma_debugfs_regs(struct dw_edma *dw)
>  	struct dentry *regs_dir;
>  	int nr_entries;
>  
> -	regs_dir = debugfs_create_dir(REGISTERS_STR, dw->debugfs);
> +	regs_dir = debugfs_create_dir(REGISTERS_STR, dw->dma.dbg_dev_root);
>  
>  	nr_entries = ARRAY_SIZE(debugfs_regs);
>  	dw_edma_debugfs_create_x32(dw, debugfs_regs, nr_entries, regs_dir);
> @@ -284,19 +284,9 @@ void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
>  	if (!debugfs_initialized())
>  		return;
>  
> -	dw->debugfs = debugfs_create_dir(dw->name, NULL);
> -
> -	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);
> +	debugfs_create_u32("mf", 0444, dw->dma.dbg_dev_root, &dw->chip->mf);
> +	debugfs_create_u16("wr_ch_cnt", 0444, dw->dma.dbg_dev_root, &dw->wr_ch_cnt);
> +	debugfs_create_u16("rd_ch_cnt", 0444, dw->dma.dbg_dev_root, &dw->rd_ch_cnt);
>  
>  	dw_edma_debugfs_regs(dw);
>  }
> -
> -void dw_edma_v0_debugfs_off(struct dw_edma_chip *chip)
> -{
> -	struct dw_edma *dw = chip->dw;
> -
> -	debugfs_remove_recursive(dw->debugfs);
> -	dw->debugfs = NULL;
> -}
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.h b/drivers/dma/dw-edma/dw-edma-v0-debugfs.h
> index d0ff25a9ea5c..eb11802c2b76 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.h
> +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.h
> @@ -13,15 +13,10 @@
>  
>  #ifdef CONFIG_DEBUG_FS
>  void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip);
> -void dw_edma_v0_debugfs_off(struct dw_edma_chip *chip);
>  #else
>  static inline void dw_edma_v0_debugfs_on(struct dw_edma_chip *chip)
>  {
>  }
> -
> -static inline void dw_edma_v0_debugfs_off(struct dw_edma_chip *chip)
> -{
> -}
>  #endif /* CONFIG_DEBUG_FS */
>  
>  #endif /* _DW_EDMA_V0_DEBUG_FS_H */
> -- 
> 2.35.1
> 

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

* Re: [PATCH 20/25] dmaengine: dw-edma: Use non-atomic io-64 methods
  2022-03-24  1:48 ` [PATCH 20/25] dmaengine: dw-edma: Use non-atomic io-64 methods Serge Semin
@ 2022-03-25  8:28   ` Manivannan Sadhasivam
  2022-04-18 11:37     ` Serge Semin
  0 siblings, 1 reply; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-25  8:28 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:31AM +0300, Serge Semin wrote:
> Instead of splitting the 64-bits IOs up into two 32-bits ones it's
> possible to use an available set of the non-atomic readq/writeq methods
> implemented exactly for such cases. They are defined in the dedicated
> header files io-64-nonatomic-lo-hi.h/io-64-nonatomic-hi-lo.h. So in case
> if the 64-bits readq/writeq methods are unavailable on some platforms at
> consideration, the corresponding drivers can have any of these headers
> included and stop locally re-implementing the 64-bits IO accessors taking
> into account the non-atomic nature of the included methods. Let's do that
> in the DW eDMA driver too. Note by doing so we can discard the
> CONFIG_64BIT config ifdefs from the code. Also note that if a platform
> doesn't support 64-bit DBI IOs then the corresponding accessors will just
> directly call the lo_hi_readq()/lo_hi_writeq() methods.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/dma/dw-edma/dw-edma-v0-core.c | 71 +++++++++------------------
>  1 file changed, 24 insertions(+), 47 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> index 6b303d5a6b2a..ebb860e19c75 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> @@ -8,6 +8,8 @@
>  
>  #include <linux/bitfield.h>
>  
> +#include <linux/io-64-nonatomic-lo-hi.h>
> +
>  #include "dw-edma-core.h"
>  #include "dw-edma-v0-core.h"
>  #include "dw-edma-v0-regs.h"
> @@ -53,8 +55,6 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
>  		SET_32(dw, rd_##name, value);		\
>  	} while (0)
>  
> -#ifdef CONFIG_64BIT
> -
>  #define SET_64(dw, name, value)				\
>  	writeq(value, &(__dw_regs(dw)->name))
>  
> @@ -80,8 +80,6 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
>  		SET_64(dw, rd_##name, value);		\
>  	} while (0)
>  
> -#endif /* CONFIG_64BIT */
> -
>  #define SET_COMPAT(dw, name, value)			\
>  	writel(value, &(__dw_regs(dw)->type.unroll.name))
>  
> @@ -164,14 +162,13 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  #define SET_LL_32(ll, value) \
>  	writel(value, ll)
>  
> -#ifdef CONFIG_64BIT
> -
>  static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  			     u64 value, void __iomem *addr)
>  {
> +	unsigned long flags;
> +
>  	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
>  		u32 viewport_sel;
> -		unsigned long flags;
>  
>  		raw_spin_lock_irqsave(&dw->lock, flags);
>  
> @@ -181,22 +178,25 @@ static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  
>  		writel(viewport_sel,
>  		       &(__dw_regs(dw)->type.legacy.viewport_sel));
> +	}
> +
> +	if (dw->chip->flags & DW_EDMA_CHIP_32BIT_DBI)
> +		lo_hi_writeq(value, addr);
> +	else
>  		writeq(value, addr);
>  
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY)
>  		raw_spin_unlock_irqrestore(&dw->lock, flags);
> -	} else {
> -		writeq(value, addr);
> -	}
>  }
>  
>  static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  			   const void __iomem *addr)
>  {
> -	u32 value;
> +	unsigned long flags;
> +	u64 value;
>  
>  	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
>  		u32 viewport_sel;
> -		unsigned long flags;
>  
>  		raw_spin_lock_irqsave(&dw->lock, flags);
>  
> @@ -206,12 +206,15 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  
>  		writel(viewport_sel,
>  		       &(__dw_regs(dw)->type.legacy.viewport_sel));
> +	}
> +
> +	if (dw->chip->flags & DW_EDMA_CHIP_32BIT_DBI)
> +		value = lo_hi_readq(addr);
> +	else
>  		value = readq(addr);
>  
> +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY)
>  		raw_spin_unlock_irqrestore(&dw->lock, flags);
> -	} else {
> -		value = readq(addr);
> -	}
>  
>  	return value;
>  }
> @@ -225,8 +228,6 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
>  #define SET_LL_64(ll, value) \
>  	writeq(value, ll)
>  
> -#endif /* CONFIG_64BIT */
> -
>  /* eDMA management callbacks */
>  void dw_edma_v0_core_off(struct dw_edma *dw)
>  {
> @@ -325,19 +326,10 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
>  		/* Transfer size */
>  		SET_LL_32(&lli[i].transfer_size, child->sz);
>  		/* SAR */
> -		#ifdef CONFIG_64BIT
> -			SET_LL_64(&lli[i].sar.reg, child->sar);
> -		#else /* CONFIG_64BIT */
> -			SET_LL_32(&lli[i].sar.lsb, lower_32_bits(child->sar));
> -			SET_LL_32(&lli[i].sar.msb, upper_32_bits(child->sar));
> -		#endif /* CONFIG_64BIT */
> +		SET_LL_64(&lli[i].sar.reg, child->sar);

This macro still uses writeq(), that's not available on 32bit platforms.
Am I missing anything?

Thanks,
Mani

>  		/* DAR */
> -		#ifdef CONFIG_64BIT
> -			SET_LL_64(&lli[i].dar.reg, child->dar);
> -		#else /* CONFIG_64BIT */
> -			SET_LL_32(&lli[i].dar.lsb, lower_32_bits(child->dar));
> -			SET_LL_32(&lli[i].dar.msb, upper_32_bits(child->dar));
> -		#endif /* CONFIG_64BIT */
> +		SET_LL_64(&lli[i].dar.reg, child->dar);
> +
>  		i++;
>  	}
>  
> @@ -349,12 +341,7 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
>  	/* Channel control */
>  	SET_LL_32(&llp->control, control);
>  	/* Linked list */
> -	#ifdef CONFIG_64BIT
> -		SET_LL_64(&llp->llp.reg, chunk->ll_region.paddr);
> -	#else /* CONFIG_64BIT */
> -		SET_LL_32(&llp->llp.lsb, lower_32_bits(chunk->ll_region.paddr));
> -		SET_LL_32(&llp->llp.msb, upper_32_bits(chunk->ll_region.paddr));
> -	#endif /* CONFIG_64BIT */
> +	SET_LL_64(&llp->llp.reg, chunk->ll_region.paddr);
>  }
>  
>  void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> @@ -417,18 +404,8 @@ 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 */
> -		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));
> -		} else {
> -		#ifdef CONFIG_64BIT
> -			SET_CH_64(dw, chan->dir, chan->id, llp.reg,
> -				  chunk->ll_region.paddr);
> -		#endif
> -		}
> +		SET_CH_64(dw, chan->dir, chan->id, llp.reg,
> +			  chunk->ll_region.paddr);
>  	}
>  	/* Doorbell */
>  	SET_RW_32(dw, chan->dir, doorbell,
> -- 
> 2.35.1
> 

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

* Re: [PATCH 21/25] dmaengine: dw-edma: Drop DT-region allocation
  2022-03-24  1:48 ` [PATCH 21/25] dmaengine: dw-edma: Drop DT-region allocation Serge Semin
@ 2022-03-25  8:33   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-25  8:33 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:32AM +0300, Serge Semin wrote:
> There is no point in allocating an additional memory for the data target
> regions passed then to the client drivers. Just use the already available
> structures defined in the dw_edma_chip instance.
> 
> Note these regions are unused in normal circumstances since they are
> specific to the case of eDMA being embedded into the DW PCIe End-point and
> having it's CSRs accessible over a End-point' BAR. This case is only known
> to be implemented as a part of the Synopsys PCIe EndPoint IP prototype
> kit.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

Thanks,
Mani

> ---
>  drivers/dma/dw-edma/dw-edma-core.c | 21 ++++-----------------
>  1 file changed, 4 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index bc530f0a2468..dbe1119fd1d2 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -744,7 +744,6 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
>  static int dw_edma_channel_setup(struct dw_edma_chip *chip, u32 wr_alloc,
>  				 u32 rd_alloc)
>  {
> -	struct dw_edma_region *dt_region;
>  	struct device *dev = chip->dev;
>  	struct dw_edma *dw = chip->dw;
>  	struct dw_edma_chan *chan;
> @@ -761,12 +760,6 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, u32 wr_alloc,
>  	for (i = 0; i < ch_cnt; i++) {
>  		chan = &dw->chan[i];
>  
> -		dt_region = devm_kzalloc(dev, sizeof(*dt_region), GFP_KERNEL);
> -		if (!dt_region)
> -			return -ENOMEM;
> -
> -		chan->vc.chan.private = dt_region;
> -
>  		chan->dw = dw;
>  
>  		if (i < dw->wr_ch_cnt) {
> @@ -814,17 +807,11 @@ static int dw_edma_channel_setup(struct dw_edma_chip *chip, u32 wr_alloc,
>  			 chan->msi.data);
>  
>  		chan->vc.desc_free = vchan_free_desc;
> -		vchan_init(&chan->vc, dma);
> +		chan->vc.chan.private = chan->dir == EDMA_DIR_WRITE ?
> +					&dw->chip->dt_region_wr[chan->id] :
> +					&dw->chip->dt_region_rd[chan->id];
>  
> -		if (chan->dir == EDMA_DIR_WRITE) {
> -			dt_region->paddr = chip->dt_region_wr[chan->id].paddr;
> -			dt_region->vaddr = chip->dt_region_wr[chan->id].vaddr;
> -			dt_region->sz = chip->dt_region_wr[chan->id].sz;
> -		} else {
> -			dt_region->paddr = chip->dt_region_rd[chan->id].paddr;
> -			dt_region->vaddr = chip->dt_region_rd[chan->id].vaddr;
> -			dt_region->sz = chip->dt_region_rd[chan->id].sz;
> -		}
> +		vchan_init(&chan->vc, dma);
>  
>  		dw_edma_v0_core_device_config(chan);
>  	}
> -- 
> 2.35.1
> 

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

* Re: [PATCH 22/25] dmaengine: dw-edma: Replace chip ID number with device name
  2022-03-24  1:48 ` [PATCH 22/25] dmaengine: dw-edma: Replace chip ID number with device name Serge Semin
@ 2022-03-25 10:02   ` Manivannan Sadhasivam
  2022-04-18 12:17     ` Serge Semin
  0 siblings, 1 reply; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-25 10:02 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:33AM +0300, Serge Semin wrote:
> Using some abstract number as the DW eDMA chip identifier isn't really
> practical. First of all there can be more than one DW eDMA controller on
> the platform some of them can be detected as the PCIe end-points, some of
> them can be embedded into the DW PCIe Root Port/End-point controllers.
> Seeing some abstract number in for instance IRQ handlers list doesn't give
> a notion regarding their reference to the particular DMA controller.
> Secondly current DW eDMA chip id implementation doesn't provide the
> multi-eDMA platforms support for same reason of possibly having eDMA
> detected on different system buses. At the same time re-implementing
> something ida-based won't give much benefits especially seeing the DW eDMA
> chip ID is only used in the IRQ request procedure. So to speak in order to
> preserve the code simplicity and get to have the multi-eDMA platforms
> support let's just use the parental device name to create the DW eDMA
> controller name.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/dma/dw-edma/dw-edma-core.c | 3 ++-
>  drivers/dma/dw-edma/dw-edma-core.h | 2 +-
>  drivers/dma/dw-edma/dw-edma-pcie.c | 1 -
>  include/linux/dma/edma.h           | 1 -
>  4 files changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index dbe1119fd1d2..72a51970bfba 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -970,7 +970,8 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>  	if (!dw->chan)
>  		return -ENOMEM;
>  
> -	snprintf(dw->name, sizeof(dw->name), "dw-edma-core:%d", chip->id);
> +	snprintf(dw->name, sizeof(dw->name), "dw-edma-core:%s",
> +		 dev_name(chip->dev));
>  
>  	/* Disable eDMA, only to establish the ideal initial conditions */
>  	dw_edma_v0_core_off(dw);
> diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
> index 980adb079182..dc25798d4ba9 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.h
> +++ b/drivers/dma/dw-edma/dw-edma-core.h
> @@ -96,7 +96,7 @@ struct dw_edma_irq {
>  };
>  
>  struct dw_edma {
> -	char				name[20];
> +	char				name[30];

I'm not sure if this length is sufficient. Other than this,

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

Thanks,
Mani

>  
>  	struct dma_device		dma;
>  
> diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> index f530bacfd716..3f9dadc73854 100644
> --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> @@ -222,7 +222,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  
>  	/* Data structure initialization */
>  	chip->dev = dev;
> -	chip->id = pdev->devfn;
>  
>  	chip->mf = vsec_data.mf;
>  	chip->nr_irqs = nr_irqs;
> diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> index 5cc87cfdd685..241c5a97ddf4 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -73,7 +73,6 @@ enum dw_edma_map_format {
>   */
>  struct dw_edma_chip {
>  	struct device		*dev;
> -	int			id;
>  	int			nr_irqs;
>  	const struct dw_edma_core_ops   *ops;
>  	u32			flags;
> -- 
> 2.35.1
> 

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

* Re: [PATCH 23/25] dmaengine: dw-edma: Bypass dma-ranges mapping for the local setup
  2022-03-24  1:48 ` [PATCH 23/25] dmaengine: dw-edma: Bypass dma-ranges mapping for the local setup Serge Semin
@ 2022-03-25 18:10   ` Manivannan Sadhasivam
  2022-04-18 13:36     ` Serge Semin
  0 siblings, 1 reply; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-25 18:10 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:34AM +0300, Serge Semin wrote:
> DW eDMA doesn't perform any translation of the traffic generated on the
> CPU/Application side. It just generates read/write AXI-bus requests with
> the specified addresses. But in case if the dma-ranges DT-property is
> specified for a platform device node, Linux will use it to map the CPU
> memory regions into the DMAable bus ranges. This isn't what we want for
> the eDMA embedded into the locally accessed DW PCIe Root Port and
> End-point. In order to work that around let's set the chan_dma_dev flag
> for each DW eDMA channel thus forcing the client drivers to getting a
> custom dma-ranges-less parental device for the mappings.
> 
> Note it will only work for the client drivers using the
> dmaengine_get_dma_device() method to get the parental DMA device.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/dma/dw-edma/dw-edma-core.c | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index 72a51970bfba..ca5cd7c99571 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -716,6 +716,21 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
>  	if (chan->status != EDMA_ST_IDLE)
>  		return -EBUSY;
>  
> +	/* Bypass the dma-ranges based memory regions mapping since the
> +	 * inbound iATU only affects the traffic incoming from the
> +	 * PCIe bus.
> +	 */

Bypass the dma-ranges based memory regions mapping since eDMA doesn't do any
address translation for the CPU address?

Other than this,

Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

Thanks,
Mani

> +	if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
> +		dchan->dev->chan_dma_dev = true;
> +
> +		dchan->dev->device.dma_coherent = chan->dw->chip->dev->dma_coherent;
> +		dma_coerce_mask_and_coherent(&dchan->dev->device,
> +					     dma_get_mask(chan->dw->chip->dev));
> +		dchan->dev->device.dma_parms = chan->dw->chip->dev->dma_parms;
> +	} else {
> +		dchan->dev->chan_dma_dev = false;
> +	}
> +
>  	pm_runtime_get(chan->dw->chip->dev);
>  
>  	return 0;
> -- 
> 2.35.1
> 

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

* Re: [PATCH 24/25] dmaengine: dw-edma: Skip cleanup procedure if no private data found
  2022-03-24  1:48 ` [PATCH 24/25] dmaengine: dw-edma: Skip cleanup procedure if no private data found Serge Semin
@ 2022-03-25 18:15   ` Manivannan Sadhasivam
  2022-04-18 13:48     ` Serge Semin
  0 siblings, 1 reply; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-25 18:15 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:35AM +0300, Serge Semin wrote:
> DW eDMA driver private data is preserved in the passed DW eDMA chip info
> structure. If either probe procedure failed or for some reason the passed
> info object doesn't have private data pointer initialized we need to halt
> the DMA device cleanup procedure in order to prevent possible system
> crashes.
> 

How come remove() could happen when probe() failed? If you hit this issue then
something else is utterly going wrong.

Thanks,
Mani

> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  drivers/dma/dw-edma/dw-edma-core.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index ca5cd7c99571..b932682a8ba8 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -1030,6 +1030,10 @@ int dw_edma_remove(struct dw_edma_chip *chip)
>  	struct dw_edma *dw = chip->dw;
>  	int i;
>  
> +	/* Skip removal if no private data found */
> +	if (!dw)
> +		return -ENODEV;
> +
>  	/* Disable eDMA */
>  	dw_edma_v0_core_off(dw);
>  
> -- 
> 2.35.1
> 

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

* Re: [PATCH 25/25] PCI: dwc: Add DW eDMA engine support
  2022-03-24  1:48 ` [PATCH 25/25] PCI: dwc: Add DW eDMA engine support Serge Semin
@ 2022-03-28 14:15   ` Manivannan Sadhasivam
  2022-04-19 20:54     ` Serge Semin
  0 siblings, 1 reply; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-28 14:15 UTC (permalink / raw)
  To: Serge Semin
  Cc: Gustavo Pimentel, Vinod Koul, Jingoo Han, Bjorn Helgaas,
	Frank Li, Lorenzo Pieralisi, Rob Herring,
	Krzysztof Wilczyński, Serge Semin, Alexey Malahov,
	Pavel Parkhomenko, linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 04:48:36AM +0300, Serge Semin wrote:
> Since the DW eDMA driver now supports eDMA controllers embedded into the
> locally accessible DW PCIe Root Ports and End-points, we can use the
> updated interface to register DW eDMA as DMA engine device if it's
> available. In order to successfully do that the DW PCIe core driver need
> to perform some preparations first. First of all it needs to find out the
> eDMA controller CSRs base address, whether they are accessible over the
> Port Logic or iATU unrolled space. Afterwards it can try to auto-detect
> the eDMA controller availability and number of it's read/write channels.
> If none was found the procedure will just silently halt with no error
> returned. Secondly the platform is supposed to provide either combined or
> per-channel IRQ signals. If no valid IRQs set is found the procedure will
> also halt with no error returned so to be backward compatible with
> platforms where DW PCIe controllers have eDMA embedded but lack of the
> IRQs defined for them. Finally before actually probing the eDMA device we
> need to allocate LLP items buffers. After that the DW eDMA can be
> registered. If registration is successful the info-message regarding the
> number of detected Read/Write eDMA channels will be printed to the system
> log in the same way as it's done for iATU settings.
> 
> Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> ---
>  .../pci/controller/dwc/pcie-designware-ep.c   |   4 +
>  .../pci/controller/dwc/pcie-designware-host.c |  13 +-
>  drivers/pci/controller/dwc/pcie-designware.c  | 188 ++++++++++++++++++
>  drivers/pci/controller/dwc/pcie-designware.h  |  23 ++-
>  4 files changed, 225 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> index 23401f17e8f0..b2840d1a5b9a 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> @@ -712,6 +712,10 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
>  
>  	dw_pcie_iatu_detect(pci);
>  
> +	ret = dw_pcie_edma_detect(pci);
> +	if (ret)
> +		return ret;
> +
>  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
>  	if (!res)
>  		return -EINVAL;

eDMA needs to be removed on error path

> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index 715a13b90e43..048b452ee4f3 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -405,14 +405,18 @@ int dw_pcie_host_init(struct pcie_port *pp)
>  
>  	dw_pcie_iatu_detect(pci);
>  
> -	ret = dw_pcie_setup_rc(pp);
> +	ret = dw_pcie_edma_detect(pci);
>  	if (ret)
>  		goto err_free_msi;
>  
> +	ret = dw_pcie_setup_rc(pp);
> +	if (ret)
> +		goto err_edma_remove;
> +
>  	if (!dw_pcie_link_up(pci) && pci->ops && pci->ops->start_link) {
>  		ret = pci->ops->start_link(pci);
>  		if (ret)
> -			goto err_free_msi;
> +			goto err_edma_remove;
>  	}
>  
>  	/* Ignore errors, the link may come up later */
> @@ -430,6 +434,9 @@ int dw_pcie_host_init(struct pcie_port *pp)
>  	if (pci->ops && pci->ops->stop_link)
>  		pci->ops->stop_link(pci);
>  
> +err_edma_remove:
> +	dw_pcie_edma_remove(pci);
> +
>  err_free_msi:
>  	if (pp->has_msi_ctrl)
>  		dw_pcie_free_msi(pp);
> @@ -452,6 +459,8 @@ void dw_pcie_host_deinit(struct pcie_port *pp)
>  	if (pci->ops && pci->ops->stop_link)
>  		pci->ops->stop_link(pci);
>  
> +	dw_pcie_edma_remove(pci);
> +
>  	if (pp->has_msi_ctrl)
>  		dw_pcie_free_msi(pp);
>  
> diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> index 4a95a7b112e9..dbe39a7ecb71 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.c
> +++ b/drivers/pci/controller/dwc/pcie-designware.c

[...]

> +int dw_pcie_edma_detect(struct dw_pcie *pci)
> +{
> +	int ret;
> +
> +	pci->edma.dev = pci->dev;
> +	if (!pci->edma.ops)
> +		pci->edma.ops = &dw_pcie_edma_ops;
> +	pci->edma.flags |= DW_EDMA_CHIP_LOCAL;
> +
> +	pci->edma_unroll_enabled = dw_pcie_edma_unroll_enabled(pci);

Is is possible to continue the unroll path for eDMA if iATU unroll is enabled?

> +	if (pci->edma_unroll_enabled && pci->iatu_unroll_enabled) {
> +		pci->edma.mf = EDMA_MF_EDMA_UNROLL;
> +		if (pci->atu_base != pci->dbi_base + DEFAULT_DBI_ATU_OFFSET)
> +			pci->edma.reg_base = pci->atu_base + PCIE_DMA_UNROLL_BASE;
> +		else
> +			pci->edma.reg_base = pci->dbi_base + DEFAULT_DBI_DMA_OFFSET;

This assumption won't work on all platforms. Atleast on our platform, the
offsets vary. So I'd suggest to try getting the reg_base from DT first and use
these offsets as a fallback as we do for iATU.

> +	} else {
> +		pci->edma.mf = EDMA_MF_EDMA_LEGACY;
> +		pci->edma.reg_base = pci->dbi_base + PCIE_DMA_VIEWPORT_BASE;
> +	}
> +
> +	ret = dw_pcie_edma_detect_channels(pci);
> +	if (ret) {
> +		dev_err(pci->dev, "Unexpected NoF eDMA channels found\n");
> +		return ret;
> +	}
> +
> +	/* Skip any further initialization if no eDMA found */

Should we introduce a new Kconfig option for enabling eDMA? My concern here is,
if eDMA is really needed for an usecase and if the platform support is broken
somehow (DT issues?), then we'll just simply go ahead without probe failure and
it may break somewhere else.

And we are returning errors if something wrong happens during eDMA probe. This
might annoy the existing users who don't care about eDMA but turning those
errors to debug will affect the real users of eDMA.

For these reasons, I think it'd be better to probe eDMA only if the Kconfig
option is enabled (which would be disabled by default). And properly return the
failure.

Thanks,
Mani

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

* Re: [PATCH 04/25] dmaengine: Fix dma_slave_config.dst_addr description
  2022-03-24 14:08   ` Manivannan Sadhasivam
@ 2022-03-31  5:38     ` Vinod Koul
  2022-03-31  7:13       ` Serge Semin
  0 siblings, 1 reply; 79+ messages in thread
From: Vinod Koul @ 2022-03-31  5:38 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Gustavo Pimentel, Jingoo Han, Bjorn Helgaas,
	Frank Li, Serge Semin, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On 24-03-22, 19:38, Manivannan Sadhasivam wrote:
> On Thu, Mar 24, 2022 at 04:48:15AM +0300, Serge Semin wrote:
> > Most likely due to a copy-paste mistake the dst_addr member of the
> > dma_slave_config structure has been marked as ignored if the !source!
> > address belong to the memory. That is relevant to the src_addr field of
> > the structure while the dst_addr field as containing a destination device
> > address is supposed to be ignored if the destination is the CPU memory.
> > Let's fix the field description accordingly.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> 
> Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> 
> One suggestion below.
> 
> > ---
> >  include/linux/dmaengine.h | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> > index 842d4f7ca752..f204ea16ac1c 100644
> > --- a/include/linux/dmaengine.h
> > +++ b/include/linux/dmaengine.h
> > @@ -395,7 +395,7 @@ enum dma_slave_buswidth {
> >   * should be read (RX), if the source is memory this argument is
> >   * ignored.
> >   * @dst_addr: this is the physical address where DMA slave data
> > - * should be written (TX), if the source is memory this argument
> > + * should be written (TX), if the destination is memory this argument
> 
> Should we rename "memory" to "local memory" or something similar?

what do you mean by local memory :)

-- 
~Vinod

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

* Re: [PATCH 04/25] dmaengine: Fix dma_slave_config.dst_addr description
  2022-03-31  5:38     ` Vinod Koul
@ 2022-03-31  7:13       ` Serge Semin
  2022-03-31 10:50         ` Manivannan Sadhasivam
  0 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-03-31  7:13 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Manivannan Sadhasivam, Serge Semin, Gustavo Pimentel, Jingoo Han,
	Bjorn Helgaas, Frank Li, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 31, 2022 at 11:08:06AM +0530, Vinod Koul wrote:
> On 24-03-22, 19:38, Manivannan Sadhasivam wrote:
> > On Thu, Mar 24, 2022 at 04:48:15AM +0300, Serge Semin wrote:
> > > Most likely due to a copy-paste mistake the dst_addr member of the
> > > dma_slave_config structure has been marked as ignored if the !source!
> > > address belong to the memory. That is relevant to the src_addr field of
> > > the structure while the dst_addr field as containing a destination device
> > > address is supposed to be ignored if the destination is the CPU memory.
> > > Let's fix the field description accordingly.
> > > 
> > > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > 
> > Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > 
> > One suggestion below.
> > 
> > > ---
> > >  include/linux/dmaengine.h | 2 +-
> > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > > 
> > > diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> > > index 842d4f7ca752..f204ea16ac1c 100644
> > > --- a/include/linux/dmaengine.h
> > > +++ b/include/linux/dmaengine.h
> > > @@ -395,7 +395,7 @@ enum dma_slave_buswidth {
> > >   * should be read (RX), if the source is memory this argument is
> > >   * ignored.
> > >   * @dst_addr: this is the physical address where DMA slave data
> > > - * should be written (TX), if the source is memory this argument
> > > + * should be written (TX), if the destination is memory this argument
> >
 
> > Should we rename "memory" to "local memory" or something similar?
> 
> what do you mean by local memory :)

Most likely Manivannan just confused the whole eDMA device specifics
with this patch purpose. This commit has nothing to do with "local"
and "remote" device memory. Such definitions are relevant to the DW
eDMA setups (whether device is integrated into the PCIe Host/End-point
controller then the CPU memory is a local memory for it, or it's a
remote PCI End-point, then the CPU memory is a remote memory for it).

Guys. Regarding the patchsets review procedure. I notice all the
comments. Just didn't have time to respond so far. Will do that till
the end of the week.

-Sergey

> 
> -- 
> ~Vinod

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

* Re: [PATCH 04/25] dmaengine: Fix dma_slave_config.dst_addr description
  2022-03-31  7:13       ` Serge Semin
@ 2022-03-31 10:50         ` Manivannan Sadhasivam
  0 siblings, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-03-31 10:50 UTC (permalink / raw)
  To: Serge Semin
  Cc: Vinod Koul, Serge Semin, Gustavo Pimentel, Jingoo Han,
	Bjorn Helgaas, Frank Li, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 31, 2022 at 10:13:43AM +0300, Serge Semin wrote:
> On Thu, Mar 31, 2022 at 11:08:06AM +0530, Vinod Koul wrote:
> > On 24-03-22, 19:38, Manivannan Sadhasivam wrote:
> > > On Thu, Mar 24, 2022 at 04:48:15AM +0300, Serge Semin wrote:
> > > > Most likely due to a copy-paste mistake the dst_addr member of the
> > > > dma_slave_config structure has been marked as ignored if the !source!
> > > > address belong to the memory. That is relevant to the src_addr field of
> > > > the structure while the dst_addr field as containing a destination device
> > > > address is supposed to be ignored if the destination is the CPU memory.
> > > > Let's fix the field description accordingly.
> > > > 
> > > > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > > 
> > > Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > > 
> > > One suggestion below.
> > > 
> > > > ---
> > > >  include/linux/dmaengine.h | 2 +-
> > > >  1 file changed, 1 insertion(+), 1 deletion(-)
> > > > 
> > > > diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> > > > index 842d4f7ca752..f204ea16ac1c 100644
> > > > --- a/include/linux/dmaengine.h
> > > > +++ b/include/linux/dmaengine.h
> > > > @@ -395,7 +395,7 @@ enum dma_slave_buswidth {
> > > >   * should be read (RX), if the source is memory this argument is
> > > >   * ignored.
> > > >   * @dst_addr: this is the physical address where DMA slave data
> > > > - * should be written (TX), if the source is memory this argument
> > > > + * should be written (TX), if the destination is memory this argument
> > >
>  
> > > Should we rename "memory" to "local memory" or something similar?
> > 
> > what do you mean by local memory :)
> 
> Most likely Manivannan just confused the whole eDMA device specifics
> with this patch purpose. This commit has nothing to do with "local"
> and "remote" device memory. Such definitions are relevant to the DW
> eDMA setups (whether device is integrated into the PCIe Host/End-point
> controller then the CPU memory is a local memory for it, or it's a
> remote PCI End-point, then the CPU memory is a remote memory for it).
> 

Ah, yes indeed. While I was reviewing the eDMA patches I just went with that
context. Sorry for the noise.

Thanks,
Mani

> Guys. Regarding the patchsets review procedure. I notice all the
> comments. Just didn't have time to respond so far. Will do that till
> the end of the week.
> 
> -Sergey
> 
> > 
> > -- 
> > ~Vinod

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

* Re: [PATCH 01/25] dmaengine: dw-edma: Drop dma_slave_config.direction field usage
  2022-03-24 13:30   ` Manivannan Sadhasivam
@ 2022-04-05 11:15     ` Serge Semin
  0 siblings, 0 replies; 79+ messages in thread
From: Serge Semin @ 2022-04-05 11:15 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 07:00:04PM +0530, Manivannan Sadhasivam wrote:
> On Thu, Mar 24, 2022 at 04:48:12AM +0300, Serge Semin wrote:
> > The dma_slave_config.direction field usage in the DW eDMA driver has been
> > introduced in the commit bd96f1b2f43a ("dmaengine: dw-edma: support local
> > dma device transfer semantics"). Mainly the change introduced there was
> > correct (indeed DEV_TO_MEM means using RD-channel and MEM_TO_DEV -
> > WR-channel for the case of having eDMA accessed locally from
> > CPU/Application side), but providing an additional
> > MEM_TO_MEM/DEV_TO_DEV-based semantics was quite redundant if not to say
> > potentially harmful (when it comes to removing the denoted field). First
> > of all since the dma_slave_config.direction field has been marked as
> > obsolete (see [1] and the structure dc [2]) and will be discarded in
> > future, using it especially in a non-standard way is discouraged. Secondly
> > in accordance with the commit denoted above the default
> > dw_edma_device_transfer() semantics has been changed despite what it's
> > message said. So claiming that the method was left backward compatible was
> > wrong.
> > 
> > Anyway let's fix the problems denoted above and simplify the
> > dw_edma_device_transfer() method by dropping the parsing of the
> > DMA-channel direction field. Instead of having that implicit
> > dma_slave_config.direction field semantic we can use the recently added
> > DW_EDMA_CHIP_LOCAL flag to distinguish between the local and remote DW
> > eDMA setups thus preserving both cases support. In addition to that an
> > ASCII-figure has been added to clarify the complication out.
> > 
> > [1] Documentation/driver-api/dmaengine/provider.rst
> > [2] include/linux/dmaengine.h: dma_slave_config.direction
> > 
> > Co-developed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > 
> > ---
> > 
> > In accordance with agreement with Frank and Manivannan this patch is
> > supposed to be moved to the series:
> > Link: https://lore.kernel.org/dmaengine/20220310192457.3090-1-Frank.Li@nxp.com/
> > in place of the patch:
> > [PATCH v5 6/9] dmaengine: dw-edma: Don't rely on the deprecated "direction" member
> > Link: https://lore.kernel.org/dmaengine/20220310192457.3090-7-Frank.Li@nxp.com/
> > ---
> >  drivers/dma/dw-edma/dw-edma-core.c | 49 +++++++++++++++++++++---------
> >  1 file changed, 34 insertions(+), 15 deletions(-)
> > 
> > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > index 5be8a5944714..e9e32ed74aa9 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > @@ -339,21 +339,40 @@ 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;
> > -		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;
> > +	/*
> > +	 * Local Root Port/End-point              Remote End-point
> > +	 * +-----------------------+ PCIe bus +----------------------+
> > +	 * |                       |    +-+   |                      |
> > +	 * |    DEV_TO_MEM   Rx Ch <----+ +---+ Tx Ch  DEV_TO_MEM    |
> > +	 * |                       |    | |   |                      |
> > +	 * |    MEM_TO_DEV   Tx Ch +----+ +---> Rx Ch  MEM_TO_DEV    |
> > +	 * |                       |    +-+   |                      |
> > +	 * +-----------------------+          +----------------------+
> > +	 *
> > +	 * 1. Normal logic:
> > +	 * If eDMA is embedded into the DW PCIe RP/EP and controlled from the
> > +	 * CPU/Application side, the Rx channel (EDMA_DIR_READ) will be used
> > +	 * for the device read operations (DEV_TO_MEM) and the Tx channel
> > +	 * (EDMA_DIR_WRITE) - for the write operations (MEM_TO_DEV).
> > +	 *
> > +	 * 2. Inverted logic:
> > +	 * If eDMA is embedded into a Remote PCIe EP and is controlled by the
> > +	 * MWr/MRd TLPs sent from the CPU's PCIe host controller, the Tx
> > +	 * channel (EDMA_DIR_WRITE) will be used for the device read operations
> > +	 * (DEV_TO_MEM) and the Rx channel (EDMA_DIR_READ) - for the write
> > +	 * operations (MEM_TO_DEV).
> > +	 *
> > +	 * It is the client driver responsibility to choose a proper channel
> > +	 * for the DMA transfers.
> > +	 */
> 

> I think it'd be good to document this using some form in "enum dw_edma_dir"
> declaration.

Well, I'd rather leave the comment here.  The dw_edma_dir enumeration
only defines the actual device channel direction, while the actual
semantics is determined by the PCIe device residence/configuration
(local + host/end-point, remote + end-point) and is reflected in the
data transfer function - dw_edma_device_transfer(). So as I see it the
comment is more suitable to be left here in the place where the
semantic is actually implemented.

-Sergey

> 
> Thanks,
> Mani
> 
> > +	if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
> > +		if ((chan->dir == EDMA_DIR_READ && dir != DMA_DEV_TO_MEM) ||
> > +		    (chan->dir == EDMA_DIR_WRITE && dir != DMA_MEM_TO_DEV))
> > +			return NULL;
> > +	} else {
> > +		if ((chan->dir == EDMA_DIR_WRITE && dir != DMA_DEV_TO_MEM) ||
> > +		    (chan->dir == EDMA_DIR_READ && dir != DMA_MEM_TO_DEV))
> > +			return NULL;
> >  	}
> >  
> >  	if (xfer->type == EDMA_XFER_CYCLIC) {
> > -- 
> > 2.35.1
> > 

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

* Re: [PATCH 03/25] dma-direct: take dma-ranges/offsets into account in resource mapping
  2022-03-24 11:30   ` Robin Murphy
@ 2022-04-17 22:44     ` Serge Semin
  2022-04-20  7:12       ` Christoph Hellwig
  0 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-04-17 22:44 UTC (permalink / raw)
  To: Robin Murphy
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Manivannan Sadhasivam,
	Christoph Hellwig, Marek Szyprowski, Vladimir Murzin,
	Alexey Malahov, Pavel Parkhomenko, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński, linux-pci, dmaengine,
	linux-kernel, iommu

Hello Robin.

Sorry for the delayed answer. My comments are below.

On Thu, Mar 24, 2022 at 11:30:38AM +0000, Robin Murphy wrote:
> On 2022-03-24 01:48, Serge Semin wrote:
> > A basic device-specific linear memory mapping was introduced back in
> > commit ("dma: Take into account dma_pfn_offset") as a single-valued offset
> > preserved in the device.dma_pfn_offset field, which was initialized for
> > instance by means of the "dma-ranges" DT property. Afterwards the
> > functionality was extended to support more than one device-specific region
> > defined in the device.dma_range_map list of maps. But all of these
> > improvements concerned a single pointer, page or sg DMA-mapping methods,
> > while the system resource mapping function turned to miss the
> > corresponding modification. Thus the dma_direct_map_resource() method now
> > just casts the CPU physical address to the device DMA address with no
> > dma-ranges-based mapping taking into account, which is obviously wrong.
> > Let's fix it by using the phys_to_dma_direct() method to get the
> > device-specific bus address from the passed memory resource for the case
> > of the directly mapped DMA.
> 

> It may not have been well-documented at the time, but this was largely
> intentional. The assumption based on known systems was that where
> dma_pfn_offset existed, it would *not* apply to peer MMIO addresses.

Well, I'd say it wasn't documented or even discussed at all. At least
after a pretty much comprehensive retrospective research I failed to
find any note about the reason of having all the dma_direct_map*()
methods converted to supporting the dma_pfn_offset/dma_range_map
ranges, but leaving the dma_direct_map_resource() method out of that
conversion. Neither it is immediately inferable from the method usage
and its prototype that it is supposed to be utilized for the DMA
memory addresses, not the CPU one.

> 
> For instance, DTs for TI Keystone 2 platforms only describe an offset for
> RAM:
> 
> 	dma-ranges = <0x80000000 0x8 0x00000000 0x80000000>;
> 
> but a DMA controller might also want to access something in the MMIO range
> 0x0-0x7fffffff, of which it still has an identical non-offset view. If a
> driver was previously using dma_map_resource() for that, it would now start
> getting DMA_MAPPING_ERROR because the dma_range_map exists but doesn't
> describe the MMIO region. I agree that in hindsight it's not an ideal
> situation, but it's how things have ended up, so at this point I'm wary of
> making potentially-breaking changes.

Hmm, what if the driver was previously using for instance the
dma_direct_map_sg() method for it? Following this logic you would have
needed to decline the whole dma_pfn_offset/dma_range_map ranges
support, since the dma_direct_map_sg(), dma_direct_map_page(),
dma_direct_alloc*() methods do take the offsets into account. What we
can see now is that the same physical address will be differently
mapped by the dma_map_resource() and, for instance, dma_map_sg()
methods. All of these methods expect to have the "phys_addr_t" address
passed, which is the CPU address, not the DMA one. Doesn't that look
erroneous? IIUC in accordance with the common kernel definition the
"resource" suffix indicates the CPU-visible address (like struct
resource range), not the DMA address. No matter whether it's used to
describe the RAM or MMIO range.

AFAICS the dma_range_map just defines the offset-based DMA-to-CPU
mapping for the particular bus/device. If the device driver already
knows the DMA address why does it need to map it at all? I see some
contradiction here.

> 
> May I ask what exactly your setup looks like, if you have a DMA controller
> with an offset view of its "own" MMIO space?

I don't have such. But what I see here is either the wrong
dma_direct_map_resource() implementation or a redundant mapping
performed in some platforms/DMA-device drivers. Indeed judging by the
dma_map_resource() method declaration it expects to have the
CPU-address passed, which will be mapped in accordance with the
"dma-ranges"-based DMA-to-CPU memory mapping in the same way as the
rest of the dma_direct-family methods. If DMA address is already known
then it is supposed to be used as-is with no any additional remapping
procedure performed.

The last but not least regarding the DMA controllers and the
dma_map_resource() usage. The dma_slave_config structure was converted
to having the CPU-physical src/dst address specified in commit
9575632052ba ("dmaengine: make slave address physical"). So the DMA
client drivers now have to set the slave source and destination
addresses defined in the CPU address space, while the DMA engine
driver needs to map it in accordance with the platform/device specific
configs.

To sum up as I see it the problem is in the dma_map_resource()
semantics still exist. The semantic isn't documented in any way while
its implementation looks confusing. You say that the method
expects to have the DMA address passed, but at the same
time it has the phys_addr argument of the phys_addr_t type. If it had
dma_addr_t type instead that would have been much less confusing.
Could you clarify whether my considerations above are wrong and in what
aspect?

-Sergey

> 
> Thanks,
> Robin.
> 
> > Fixes: 25f1e1887088 ("dma: Take into account dma_pfn_offset")
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >   kernel/dma/direct.c | 2 +-
> >   1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
> > index 50f48e9e4598..9ce8192b29ab 100644
> > --- a/kernel/dma/direct.c
> > +++ b/kernel/dma/direct.c
> > @@ -497,7 +497,7 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
> >   dma_addr_t dma_direct_map_resource(struct device *dev, phys_addr_t paddr,
> >   		size_t size, enum dma_data_direction dir, unsigned long attrs)
> >   {
> > -	dma_addr_t dma_addr = paddr;
> > +	dma_addr_t dma_addr = phys_to_dma_direct(dev, paddr);
> >   	if (unlikely(!dma_capable(dev, dma_addr, size, false))) {
> >   		dev_err_once(dev,

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

* Re: [PATCH 07/25] dmaengine: dw-edma: Don't permit non-inc interleaved xfers
  2022-03-24 17:15   ` Manivannan Sadhasivam
@ 2022-04-17 22:59     ` Serge Semin
  0 siblings, 0 replies; 79+ messages in thread
From: Serge Semin @ 2022-04-17 22:59 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Thu, Mar 24, 2022 at 10:45:12PM +0530, Manivannan Sadhasivam wrote:
> On Thu, Mar 24, 2022 at 04:48:18AM +0300, Serge Semin wrote:
> > DW eDMA controller always increments both source and destination
> > addresses. Permitting DMA interleaved transfers with no src_inc/dst_inc
> > flags set may lead to unexpected behaviour for the device users. Let's fix
> > that by terminating the interleaved transfers if at least one of the
> > dma_interleaved_template.{src_inc,dst_inc} flag is initialized with false
> > value. Note in addition to that we need we need to increase the source and
> > destination addresses accordingly after each iteration.
> > 
> 

> Can you please point me where this gets documented in databook?

10.3.1 Source and Destination Address Registers (SAR, DAR)
"...  You program the start of the local and remote data buffers using
these registers, and the DMA increments the SAR and DAR as the DMA
transfer progresses. ..."

[1] DesignWare Cores PCI Express Controller databook, v4.70a, March 2016,
    p. 882.
[2] DesignWare Cores PCI Express Controller databook, v5.40a, March 2019,
    p. 1110.

-Sergey

> 
> Thanks,
> Mani
> 
> > Fixes: 85e7518f42c8 ("dmaengine: dw-edma: Add device_prep_interleave_dma() support")
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/dma/dw-edma/dw-edma-core.c | 12 ++++++------
> >  1 file changed, 6 insertions(+), 6 deletions(-)
> > 
> > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > index 2010d7f8191f..f41bde27795c 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > @@ -386,6 +386,8 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> >  			return NULL;
> >  		if (xfer->xfer.il->numf > 0 && xfer->xfer.il->frame_size > 0)
> >  			return NULL;
> > +		if (!xfer->xfer.il->src_inc || !xfer->xfer.il->dst_inc)
> > +			return NULL;
> >  	} else {
> >  		return NULL;
> >  	}
> > @@ -485,15 +487,13 @@ dw_edma_device_transfer(struct dw_edma_transfer *xfer)
> >  			struct dma_interleaved_template *il = xfer->xfer.il;
> >  			struct data_chunk *dc = &il->sgl[i];
> >  
> > -			if (il->src_sgl) {
> > -				src_addr += burst->sz;
> > +			src_addr += burst->sz;
> > +			if (il->src_sgl)
> >  				src_addr += dmaengine_get_src_icg(il, dc);
> > -			}
> >  
> > -			if (il->dst_sgl) {
> > -				dst_addr += burst->sz;
> > +			dst_addr += burst->sz;
> > +			if (il->dst_sgl)
> >  				dst_addr += dmaengine_get_dst_icg(il, dc);
> > -			}
> >  		}
> >  	}
> >  
> > -- 
> > 2.35.1
> > 

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

* Re: [PATCH 15/25] dmaengine: dw-edma: Convert DebugFS descs to being kz-allocated
  2022-03-25  6:03   ` Manivannan Sadhasivam
  2022-03-25  6:42     ` Manivannan Sadhasivam
@ 2022-04-18  7:17     ` Serge Semin
  1 sibling, 0 replies; 79+ messages in thread
From: Serge Semin @ 2022-04-18  7:17 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Fri, Mar 25, 2022 at 11:33:49AM +0530, Manivannan Sadhasivam wrote:
> On Thu, Mar 24, 2022 at 04:48:26AM +0300, Serge Semin wrote:
> > Currently all the DW eDMA DebugFS nodes descriptors are allocated on
> > stack, while the DW eDMA driver private data and CSR limits are statically
> > preserved. Such design won't work for the multi-eDMA platforms.
> 
> Can you please explain why?
> 
> > As a
> > preparation to adding the multi-eDMA system setups support we need to have
> > each DebugFS node separately allocated and described. Afterwards we'll put
> > an addition info there like Read/Write channel flag, channel ID, DW eDMA
> > private data reference.
> > 
> > Note this conversion is mainly required due to having the legacy DW eDMA
> > controllers with indirect Read/Write channels context CSRs access. If we
> > didn't need to have a synchronized access to these registers the DebugFS
> > code of the driver would have been much simpler.
> > 
> 

> I fail to understand how this change is beneficial or the exact issue.

Just to be clear. It has only one benefit - an ability to preserve a
device-specific data in the dw_edma_debugfs_entry structure. That data
will be the dw_edma private data instance, which in it turn will be
used to access the register spin lock. All of that in general is
required to support more than one DW eDMA controllers in the system.

> 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 15 ++++++++++++---
> >  1 file changed, 12 insertions(+), 3 deletions(-)
> > 
> > diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > index afd519d9568b..7eb0147912fa 100644
> > --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > @@ -53,7 +53,8 @@ struct dw_edma_debugfs_entry {
> >  
> >  static int dw_edma_debugfs_u32_get(void *data, u64 *val)
> >  {
> > -	void __iomem *reg = data;
> > +	struct dw_edma_debugfs_entry __iomem *entry = data;
> 

> Why the entry has to be of __iomem?

Good question. It has just slipped through my fingers in from the
previous code. You are right. I should drop it.

-Sergey

> 
> Thanks,
> Mani
> 
> > +	void __iomem *reg = entry->reg;
> >  
> >  	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY &&
> >  	    reg >= (void __iomem *)&regs->type.legacy.ch) {
> > @@ -94,14 +95,22 @@ static int dw_edma_debugfs_u32_get(void *data, u64 *val)
> >  }
> >  DEFINE_DEBUGFS_ATTRIBUTE(fops_x32, dw_edma_debugfs_u32_get, NULL, "0x%08llx\n");
> >  
> > -static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry entries[],
> > +static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry ini[],
> >  				       int nr_entries, struct dentry *dir)
> >  {
> > +	struct dw_edma_debugfs_entry *entries;
> >  	int i;
> >  
> > +	entries = devm_kcalloc(dw->chip->dev, nr_entries, sizeof(*entries),
> > +			       GFP_KERNEL);
> > +	if (!entries)
> > +		return;
> > +
> >  	for (i = 0; i < nr_entries; i++) {
> > +		entries[i] = ini[i];
> > +
> >  		debugfs_create_file_unsafe(entries[i].name, 0444, dir,
> > -					   entries[i].reg, &fops_x32);
> > +					   &entries[i], &fops_x32);
> >  	}
> >  }
> >  
> > -- 
> > 2.35.1
> > 

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

* Re: [PATCH 16/25] dmaengine: dw-edma: Simplify the DebugFS context CSRs init procedure
  2022-03-25  6:27   ` Manivannan Sadhasivam
  2022-03-25  6:31     ` Manivannan Sadhasivam
@ 2022-04-18  8:23     ` Serge Semin
  1 sibling, 0 replies; 79+ messages in thread
From: Serge Semin @ 2022-04-18  8:23 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Fri, Mar 25, 2022 at 11:57:08AM +0530, Manivannan Sadhasivam wrote:
> On Thu, Mar 24, 2022 at 04:48:27AM +0300, Serge Semin wrote:
> > DW eDMA v4.70a and older have the read and write channels context CSRs
> > indirectly accessible. It means the CSRs like Channel Control, Xfer size,
> > SAR, DAR and LLP address are accessed over at a fixed MMIO address, but
> > their reference to the corresponding channel is determined by the Viewport
> > CSR. In order to have a coherent access to these registers the CSR IOs are
> > supposed to be protected with a spin-lock. DW eDMA v4.80a and newer
> > normally have unrolled Read/Write channel context registers. That is all
> > CSRs denoted before are directly mapped in the controller MMIO space.
> > 
> > Since both normal and viewport-based registers are exposed via the DebugFS
> > nodes, the original code author decided to implement an algorithm based on
> > the unrolled CSRs mapping with the viewport addresses recalculation if
> > it's required. The problem is that such implementation turned to be first
> > unscalable (supports a platform with only single eDMA available since a
> > base address statically preserved) and second needlessly overcomplicated
> > (it loops over all Rd/Wr context addresses and re-calculates the viewport
> > base address on each DebugFS node access). The algorithm can be greatly
> > simplified just by adding the channel ID and it's direction fields in the
> > eDMA DebugFS node descriptor. These new parameters can be used to find a
> > CSR offset within the corresponding channel registers space. The DW eDMA
> > DebugFS node getter afterwards will also use them in order to activate the
> > respective context CSRs viewport before reading data from the specified
> > register. In case of the unrolled version of the CSRs mapping there won't
> > be any spin-lock taken/released, no viewport activation as before this
> > modification.
> > 
> > Note this modification fixes the REGISTER() macros using an externally
> > defined local variable. The same problem with the rest of the macro will
> > be fixed in the next commit.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/dma/dw-edma/dw-edma-v0-debugfs.c | 84 +++++++++++-------------
> >  1 file changed, 38 insertions(+), 46 deletions(-)
> > 
> > diff --git a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > index 7eb0147912fa..b34a68964232 100644
> > --- a/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > +++ b/drivers/dma/dw-edma/dw-edma-v0-debugfs.c
> > @@ -15,9 +15,27 @@
> >  
> >  #define REGS_ADDR(name) \
> >  	((void __iomem *)&regs->name)
> > +
> > +#define REGS_CH_ADDR(name, _dir, _ch)						\
> > +	({									\
> > +		struct dw_edma_v0_ch_regs __iomem *__ch_regs;			\
> > +										\
> > +		if ((dw)->chip->mf == EDMA_MF_EDMA_LEGACY)			\
> > +			__ch_regs = &regs->type.legacy.ch;			\
> > +		else if (_dir == EDMA_DIR_READ)					\
> > +			__ch_regs = &regs->type.unroll.ch[_ch].rd;		\
> > +		else								\
> > +			__ch_regs = &regs->type.unroll.ch[_ch].wr;		\
> > +										\
> > +		(void __iomem *)&__ch_regs->name;				\
> > +	})
> > +
> >  #define REGISTER(name) \
> >  	{ #name, REGS_ADDR(name) }
> >  
> > +#define CTX_REGISTER(name, dir, ch) \
> > +	{ #name, REGS_CH_ADDR(name, dir, ch), dir, ch }
> 
> What is the need of "dir, ch" at the end?
> 
> > +
> >  #define WR_REGISTER(name) \
> >  	{ #name, REGS_ADDR(wr_##name) }
> >  #define RD_REGISTER(name) \
> > @@ -41,14 +59,11 @@
> >  static struct dw_edma				*dw;
> >  static struct dw_edma_v0_regs			__iomem *regs;
> >  
> > -static struct {
> > -	void					__iomem *start;
> > -	void					__iomem *end;
> > -} lim[2][EDMA_V0_MAX_NR_CH];
> > -
> >  struct dw_edma_debugfs_entry {
> >  	const char				*name;
> >  	void __iomem				*reg;
> > +	enum dw_edma_dir			dir;
> > +	u16					ch;
> >  };
> >  
> >  static int dw_edma_debugfs_u32_get(void *data, u64 *val)
> > @@ -58,33 +73,16 @@ static int dw_edma_debugfs_u32_get(void *data, u64 *val)
> >  
> >  	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;
> >  		unsigned long flags;
> > -		u16 ch;
> > -
> > -		for (ch = 0; ch < dw->wr_ch_cnt; ch++)
> > -			if (lim[0][ch].start >= reg && reg < lim[0][ch].end) {
> > -				ptr += (reg - lim[0][ch].start);
> > -				goto legacy_sel_wr;
> > -			}
> > -
> > -		for (ch = 0; ch < dw->rd_ch_cnt; ch++)
> > -			if (lim[1][ch].start >= reg && reg < lim[1][ch].end) {
> > -				ptr += (reg - lim[1][ch].start);
> > -				goto legacy_sel_rd;
> > -			}
> > -
> > -		return 0;
> > -legacy_sel_rd:
> > -		viewport_sel = BIT(31);
> > -legacy_sel_wr:
> > -		viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, ch);
> > +		u32 viewport_sel;
> > +
> > +		viewport_sel = entry->dir == EDMA_DIR_READ ? BIT(31) : 0;
> > +		viewport_sel |= FIELD_PREP(EDMA_V0_VIEWPORT_MASK, entry->ch);
> >  
> >  		raw_spin_lock_irqsave(&dw->lock, flags);
> >  
> >  		writel(viewport_sel, &regs->type.legacy.viewport_sel);
> > -		*val = readl(ptr);
> > +		*val = readl(reg);
> >  
> >  		raw_spin_unlock_irqrestore(&dw->lock, flags);
> >  	} else {
> > @@ -114,19 +112,19 @@ static void dw_edma_debugfs_create_x32(const struct dw_edma_debugfs_entry ini[],
> >  	}
> >  }
> >  
> > -static void dw_edma_debugfs_regs_ch(struct dw_edma_v0_ch_regs __iomem *regs,
> > +static void dw_edma_debugfs_regs_ch(enum dw_edma_dir edma_dir, u16 ch,
> >  				    struct dentry *dir)
> 

> Using "dir" for directory would be confusing since it could also refer
> direction. I'd suggest to use "dentry".

Agreed, but for the sake of consistency this needs to be done for the
whole file. Due to that in some context using "dentry" isn't that
suitable since makes the variables name a bit too long. I'll use
'dent' instead. The change will be submitted as a separate patch in
this series.

-Sergey

> 
> Thanks,
> Mani
> 
> >  {
> > -	const struct dw_edma_debugfs_entry debugfs_regs[] = {
> > -		REGISTER(ch_control1),
> > -		REGISTER(ch_control2),
> > -		REGISTER(transfer_size),
> > -		REGISTER(sar.lsb),
> > -		REGISTER(sar.msb),
> > -		REGISTER(dar.lsb),
> > -		REGISTER(dar.msb),
> > -		REGISTER(llp.lsb),
> > -		REGISTER(llp.msb),
> > +	struct dw_edma_debugfs_entry debugfs_regs[] = {
> > +		CTX_REGISTER(ch_control1, edma_dir, ch),
> > +		CTX_REGISTER(ch_control2, edma_dir, ch),
> > +		CTX_REGISTER(transfer_size, edma_dir, ch),
> > +		CTX_REGISTER(sar.lsb, edma_dir, ch),
> > +		CTX_REGISTER(sar.msb, edma_dir, ch),
> > +		CTX_REGISTER(dar.lsb, edma_dir, ch),
> > +		CTX_REGISTER(dar.msb, edma_dir, ch),
> > +		CTX_REGISTER(llp.lsb, edma_dir, ch),
> > +		CTX_REGISTER(llp.msb, edma_dir, ch),
> >  	};
> >  	int nr_entries;
> >  
> > @@ -191,10 +189,7 @@ static void dw_edma_debugfs_regs_wr(struct dentry *dir)
> >  
> >  		ch_dir = debugfs_create_dir(name, regs_dir);
> >  
> > -		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].wr, ch_dir);
> > -
> > -		lim[0][i].start = &regs->type.unroll.ch[i].wr;
> > -		lim[0][i].end = &regs->type.unroll.ch[i].padding_1[0];
> > +		dw_edma_debugfs_regs_ch(EDMA_DIR_WRITE, i, ch_dir);
> >  	}
> >  }
> >  
> > @@ -256,10 +251,7 @@ static void dw_edma_debugfs_regs_rd(struct dentry *dir)
> >  
> >  		ch_dir = debugfs_create_dir(name, regs_dir);
> >  
> > -		dw_edma_debugfs_regs_ch(&regs->type.unroll.ch[i].rd, ch_dir);
> > -
> > -		lim[1][i].start = &regs->type.unroll.ch[i].rd;
> > -		lim[1][i].end = &regs->type.unroll.ch[i].padding_2[0];
> > +		dw_edma_debugfs_regs_ch(EDMA_DIR_READ, i, ch_dir);
> >  	}
> >  }
> >  
> > -- 
> > 2.35.1
> > 

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

* Re: [PATCH 20/25] dmaengine: dw-edma: Use non-atomic io-64 methods
  2022-03-25  8:28   ` Manivannan Sadhasivam
@ 2022-04-18 11:37     ` Serge Semin
  0 siblings, 0 replies; 79+ messages in thread
From: Serge Semin @ 2022-04-18 11:37 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Fri, Mar 25, 2022 at 01:58:40PM +0530, Manivannan Sadhasivam wrote:
> On Thu, Mar 24, 2022 at 04:48:31AM +0300, Serge Semin wrote:
> > Instead of splitting the 64-bits IOs up into two 32-bits ones it's
> > possible to use an available set of the non-atomic readq/writeq methods
> > implemented exactly for such cases. They are defined in the dedicated
> > header files io-64-nonatomic-lo-hi.h/io-64-nonatomic-hi-lo.h. So in case
> > if the 64-bits readq/writeq methods are unavailable on some platforms at
> > consideration, the corresponding drivers can have any of these headers
> > included and stop locally re-implementing the 64-bits IO accessors taking
> > into account the non-atomic nature of the included methods. Let's do that
> > in the DW eDMA driver too. Note by doing so we can discard the
> > CONFIG_64BIT config ifdefs from the code. Also note that if a platform
> > doesn't support 64-bit DBI IOs then the corresponding accessors will just
> > directly call the lo_hi_readq()/lo_hi_writeq() methods.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/dma/dw-edma/dw-edma-v0-core.c | 71 +++++++++------------------
> >  1 file changed, 24 insertions(+), 47 deletions(-)
> > 
> > diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
> > index 6b303d5a6b2a..ebb860e19c75 100644
> > --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> > @@ -8,6 +8,8 @@
> >  
> >  #include <linux/bitfield.h>
> >  
> > +#include <linux/io-64-nonatomic-lo-hi.h>
> > +
> >  #include "dw-edma-core.h"
> >  #include "dw-edma-v0-core.h"
> >  #include "dw-edma-v0-regs.h"
> > @@ -53,8 +55,6 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
> >  		SET_32(dw, rd_##name, value);		\
> >  	} while (0)
> >  
> > -#ifdef CONFIG_64BIT
> > -
> >  #define SET_64(dw, name, value)				\
> >  	writeq(value, &(__dw_regs(dw)->name))
> >  
> > @@ -80,8 +80,6 @@ static inline struct dw_edma_v0_regs __iomem *__dw_regs(struct dw_edma *dw)
> >  		SET_64(dw, rd_##name, value);		\
> >  	} while (0)
> >  
> > -#endif /* CONFIG_64BIT */
> > -
> >  #define SET_COMPAT(dw, name, value)			\
> >  	writel(value, &(__dw_regs(dw)->type.unroll.name))
> >  
> > @@ -164,14 +162,13 @@ static inline u32 readl_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> >  #define SET_LL_32(ll, value) \
> >  	writel(value, ll)
> >  
> > -#ifdef CONFIG_64BIT
> > -
> >  static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> >  			     u64 value, void __iomem *addr)
> >  {
> > +	unsigned long flags;
> > +
> >  	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> >  		u32 viewport_sel;
> > -		unsigned long flags;
> >  
> >  		raw_spin_lock_irqsave(&dw->lock, flags);
> >  
> > @@ -181,22 +178,25 @@ static inline void writeq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> >  
> >  		writel(viewport_sel,
> >  		       &(__dw_regs(dw)->type.legacy.viewport_sel));
> > +	}
> > +
> > +	if (dw->chip->flags & DW_EDMA_CHIP_32BIT_DBI)
> > +		lo_hi_writeq(value, addr);
> > +	else
> >  		writeq(value, addr);
> >  
> > +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY)
> >  		raw_spin_unlock_irqrestore(&dw->lock, flags);
> > -	} else {
> > -		writeq(value, addr);
> > -	}
> >  }
> >  
> >  static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> >  			   const void __iomem *addr)
> >  {
> > -	u32 value;
> > +	unsigned long flags;
> > +	u64 value;
> >  
> >  	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY) {
> >  		u32 viewport_sel;
> > -		unsigned long flags;
> >  
> >  		raw_spin_lock_irqsave(&dw->lock, flags);
> >  
> > @@ -206,12 +206,15 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> >  
> >  		writel(viewport_sel,
> >  		       &(__dw_regs(dw)->type.legacy.viewport_sel));
> > +	}
> > +
> > +	if (dw->chip->flags & DW_EDMA_CHIP_32BIT_DBI)
> > +		value = lo_hi_readq(addr);
> > +	else
> >  		value = readq(addr);
> >  
> > +	if (dw->chip->mf == EDMA_MF_EDMA_LEGACY)
> >  		raw_spin_unlock_irqrestore(&dw->lock, flags);
> > -	} else {
> > -		value = readq(addr);
> > -	}
> >  
> >  	return value;
> >  }
> > @@ -225,8 +228,6 @@ static inline u64 readq_ch(struct dw_edma *dw, enum dw_edma_dir dir, u16 ch,
> >  #define SET_LL_64(ll, value) \
> >  	writeq(value, ll)
> >  
> > -#endif /* CONFIG_64BIT */
> > -
> >  /* eDMA management callbacks */
> >  void dw_edma_v0_core_off(struct dw_edma *dw)
> >  {
> > @@ -325,19 +326,10 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
> >  		/* Transfer size */
> >  		SET_LL_32(&lli[i].transfer_size, child->sz);
> >  		/* SAR */
> > -		#ifdef CONFIG_64BIT
> > -			SET_LL_64(&lli[i].sar.reg, child->sar);
> > -		#else /* CONFIG_64BIT */
> > -			SET_LL_32(&lli[i].sar.lsb, lower_32_bits(child->sar));
> > -			SET_LL_32(&lli[i].sar.msb, upper_32_bits(child->sar));
> > -		#endif /* CONFIG_64BIT */
> > +		SET_LL_64(&lli[i].sar.reg, child->sar);
> 

> This macro still uses writeq(), that's not available on 32bit platforms.
> Am I missing anything?

Yes, the writeq/readq macro are defined in the
include/linux/{io-64-nonatomic-lo-hi.h,io-64-nonatomic-hi-lo.h} files.
If the platform doesn't provide its own 64-bit IOs implementation
these macro are used and are unwrapped with the two writel/readl
methods.

-Sergey

> 
> Thanks,
> Mani
> 
> >  		/* DAR */
> > -		#ifdef CONFIG_64BIT
> > -			SET_LL_64(&lli[i].dar.reg, child->dar);
> > -		#else /* CONFIG_64BIT */
> > -			SET_LL_32(&lli[i].dar.lsb, lower_32_bits(child->dar));
> > -			SET_LL_32(&lli[i].dar.msb, upper_32_bits(child->dar));
> > -		#endif /* CONFIG_64BIT */
> > +		SET_LL_64(&lli[i].dar.reg, child->dar);
> > +
> >  		i++;
> >  	}
> >  
> > @@ -349,12 +341,7 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
> >  	/* Channel control */
> >  	SET_LL_32(&llp->control, control);
> >  	/* Linked list */
> > -	#ifdef CONFIG_64BIT
> > -		SET_LL_64(&llp->llp.reg, chunk->ll_region.paddr);
> > -	#else /* CONFIG_64BIT */
> > -		SET_LL_32(&llp->llp.lsb, lower_32_bits(chunk->ll_region.paddr));
> > -		SET_LL_32(&llp->llp.msb, upper_32_bits(chunk->ll_region.paddr));
> > -	#endif /* CONFIG_64BIT */
> > +	SET_LL_64(&llp->llp.reg, chunk->ll_region.paddr);
> >  }
> >  
> >  void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
> > @@ -417,18 +404,8 @@ 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 */
> > -		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));
> > -		} else {
> > -		#ifdef CONFIG_64BIT
> > -			SET_CH_64(dw, chan->dir, chan->id, llp.reg,
> > -				  chunk->ll_region.paddr);
> > -		#endif
> > -		}
> > +		SET_CH_64(dw, chan->dir, chan->id, llp.reg,
> > +			  chunk->ll_region.paddr);
> >  	}
> >  	/* Doorbell */
> >  	SET_RW_32(dw, chan->dir, doorbell,
> > -- 
> > 2.35.1
> > 

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

* Re: [PATCH 22/25] dmaengine: dw-edma: Replace chip ID number with device name
  2022-03-25 10:02   ` Manivannan Sadhasivam
@ 2022-04-18 12:17     ` Serge Semin
  0 siblings, 0 replies; 79+ messages in thread
From: Serge Semin @ 2022-04-18 12:17 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Fri, Mar 25, 2022 at 03:32:04PM +0530, Manivannan Sadhasivam wrote:
> On Thu, Mar 24, 2022 at 04:48:33AM +0300, Serge Semin wrote:
> > Using some abstract number as the DW eDMA chip identifier isn't really
> > practical. First of all there can be more than one DW eDMA controller on
> > the platform some of them can be detected as the PCIe end-points, some of
> > them can be embedded into the DW PCIe Root Port/End-point controllers.
> > Seeing some abstract number in for instance IRQ handlers list doesn't give
> > a notion regarding their reference to the particular DMA controller.
> > Secondly current DW eDMA chip id implementation doesn't provide the
> > multi-eDMA platforms support for same reason of possibly having eDMA
> > detected on different system buses. At the same time re-implementing
> > something ida-based won't give much benefits especially seeing the DW eDMA
> > chip ID is only used in the IRQ request procedure. So to speak in order to
> > preserve the code simplicity and get to have the multi-eDMA platforms
> > support let's just use the parental device name to create the DW eDMA
> > controller name.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/dma/dw-edma/dw-edma-core.c | 3 ++-
> >  drivers/dma/dw-edma/dw-edma-core.h | 2 +-
> >  drivers/dma/dw-edma/dw-edma-pcie.c | 1 -
> >  include/linux/dma/edma.h           | 1 -
> >  4 files changed, 3 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > index dbe1119fd1d2..72a51970bfba 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > @@ -970,7 +970,8 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> >  	if (!dw->chan)
> >  		return -ENOMEM;
> >  
> > -	snprintf(dw->name, sizeof(dw->name), "dw-edma-core:%d", chip->id);
> > +	snprintf(dw->name, sizeof(dw->name), "dw-edma-core:%s",
> > +		 dev_name(chip->dev));
> >  
> >  	/* Disable eDMA, only to establish the ideal initial conditions */
> >  	dw_edma_v0_core_off(dw);
> > diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
> > index 980adb079182..dc25798d4ba9 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.h
> > +++ b/drivers/dma/dw-edma/dw-edma-core.h
> > @@ -96,7 +96,7 @@ struct dw_edma_irq {
> >  };
> >  
> >  struct dw_edma {
> > -	char				name[20];
> > +	char				name[30];
> 

> I'm not sure if this length is sufficient. Other than this,
> 
> Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

My calculations were based on the prefix+pci-device-name length. For
instance, for the case of the remote eDMA the name length would be
strlen("dw-edma-core:0000:00:00.0") = 25 + 1 (for '\0'). There's even
some room left. Seeing the prefix is always used in the string there
will be at most 16 chars for the unique part of the name. If you
predict it to be greater than that I'll extend the length as you say.

-Sergey

> 
> Thanks,
> Mani
> 
> >  
> >  	struct dma_device		dma;
> >  
> > diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> > index f530bacfd716..3f9dadc73854 100644
> > --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> > +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> > @@ -222,7 +222,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >  
> >  	/* Data structure initialization */
> >  	chip->dev = dev;
> > -	chip->id = pdev->devfn;
> >  
> >  	chip->mf = vsec_data.mf;
> >  	chip->nr_irqs = nr_irqs;
> > diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> > index 5cc87cfdd685..241c5a97ddf4 100644
> > --- a/include/linux/dma/edma.h
> > +++ b/include/linux/dma/edma.h
> > @@ -73,7 +73,6 @@ enum dw_edma_map_format {
> >   */
> >  struct dw_edma_chip {
> >  	struct device		*dev;
> > -	int			id;
> >  	int			nr_irqs;
> >  	const struct dw_edma_core_ops   *ops;
> >  	u32			flags;
> > -- 
> > 2.35.1
> > 

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

* Re: [PATCH 23/25] dmaengine: dw-edma: Bypass dma-ranges mapping for the local setup
  2022-03-25 18:10   ` Manivannan Sadhasivam
@ 2022-04-18 13:36     ` Serge Semin
  0 siblings, 0 replies; 79+ messages in thread
From: Serge Semin @ 2022-04-18 13:36 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Fri, Mar 25, 2022 at 11:40:42PM +0530, Manivannan Sadhasivam wrote:
> On Thu, Mar 24, 2022 at 04:48:34AM +0300, Serge Semin wrote:
> > DW eDMA doesn't perform any translation of the traffic generated on the
> > CPU/Application side. It just generates read/write AXI-bus requests with
> > the specified addresses. But in case if the dma-ranges DT-property is
> > specified for a platform device node, Linux will use it to map the CPU
> > memory regions into the DMAable bus ranges. This isn't what we want for
> > the eDMA embedded into the locally accessed DW PCIe Root Port and
> > End-point. In order to work that around let's set the chan_dma_dev flag
> > for each DW eDMA channel thus forcing the client drivers to getting a
> > custom dma-ranges-less parental device for the mappings.
> > 
> > Note it will only work for the client drivers using the
> > dmaengine_get_dma_device() method to get the parental DMA device.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/dma/dw-edma/dw-edma-core.c | 15 +++++++++++++++
> >  1 file changed, 15 insertions(+)
> > 
> > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > index 72a51970bfba..ca5cd7c99571 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > @@ -716,6 +716,21 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
> >  	if (chan->status != EDMA_ST_IDLE)
> >  		return -EBUSY;
> >  
> > +	/* Bypass the dma-ranges based memory regions mapping since the
> > +	 * inbound iATU only affects the traffic incoming from the
> > +	 * PCIe bus.
> > +	 */
> 

> Bypass the dma-ranges based memory regions mapping since eDMA doesn't do any
> address translation for the CPU address?

Seems reasonable. I'll fix the comment to being clearer.

BTW since we omit setting the DMA_BYPASS flag of the outbound iATU
windows, the DMA address is actually affected by the DW PCIe
controller but in a bit of a sophisticated way. AFAIU if no DMA_BYPASS
flag specified and the resultant TLP address falls into any outbound
iATU window, the address will be translated in accordance with that
window translation rule. So happen the chains like this:
+ DMA write:
CPU memory <-,-> eDMA LLi:SAR(CPU address, data) -> eDMA LLi:DAR(DMA address, data) ->
Outbound iATU TLP MWr(PCIe address, data) -> PCIe memory.
+ DMA read:
eDMA SAR(DMA address, ?) -> Outbound iATU TLP MRd(PCIe address, ?) ->
PCIe memory -> Outbound iATU TLP MRd(PCIe address, data) -> eDMA
SAR(DMA address, data) -> eDMA DAR(CPU address, data) -> CPU memory

Due to that handy feature we don't need to search for the PCIe bus
memory range matching the passed source and destination DMA addresses
of the SG-lists. It is done by the Outbound iATU engine automatically.
If the DMA_BYPASS flag was set, all the Outbound iATU-related stages
would have been omitted from the diagram above and the DMA<->PCIe
translations would have needed to be performed in the eDMA driver
code.

-Sergey

> 
> Other than this,
> 
> Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> 
> Thanks,
> Mani
> 
> > +	if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) {
> > +		dchan->dev->chan_dma_dev = true;
> > +
> > +		dchan->dev->device.dma_coherent = chan->dw->chip->dev->dma_coherent;
> > +		dma_coerce_mask_and_coherent(&dchan->dev->device,
> > +					     dma_get_mask(chan->dw->chip->dev));
> > +		dchan->dev->device.dma_parms = chan->dw->chip->dev->dma_parms;
> > +	} else {
> > +		dchan->dev->chan_dma_dev = false;
> > +	}
> > +
> >  	pm_runtime_get(chan->dw->chip->dev);
> >  
> >  	return 0;
> > -- 
> > 2.35.1
> > 

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

* Re: [PATCH 24/25] dmaengine: dw-edma: Skip cleanup procedure if no private data found
  2022-03-25 18:15   ` Manivannan Sadhasivam
@ 2022-04-18 13:48     ` Serge Semin
  2022-04-23 14:45       ` Manivannan Sadhasivam
  0 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-04-18 13:48 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Fri, Mar 25, 2022 at 11:45:03PM +0530, Manivannan Sadhasivam wrote:
> On Thu, Mar 24, 2022 at 04:48:35AM +0300, Serge Semin wrote:
> > DW eDMA driver private data is preserved in the passed DW eDMA chip info
> > structure. If either probe procedure failed or for some reason the passed
> > info object doesn't have private data pointer initialized we need to halt
> > the DMA device cleanup procedure in order to prevent possible system
> > crashes.
> > 
> 

> How come remove() could happen when probe() failed? If you hit this issue then
> something else is utterly going wrong.

It fully depends on the DW eDMA client driver implementation, which
can't and in general shouldn't be guessed. But what must be done in
the DW eDMA driver is a protection against the invalid data being
passed to the exported API methods. That wrong situation must be
detected and handled in the API user code. It's much easier to do by
having an error code returned from the dw_edma_remove() method than
catching random system crashes.

-Sergey

> 
> Thanks,
> Mani
> 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  drivers/dma/dw-edma/dw-edma-core.c | 4 ++++
> >  1 file changed, 4 insertions(+)
> > 
> > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > index ca5cd7c99571..b932682a8ba8 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > @@ -1030,6 +1030,10 @@ int dw_edma_remove(struct dw_edma_chip *chip)
> >  	struct dw_edma *dw = chip->dw;
> >  	int i;
> >  
> > +	/* Skip removal if no private data found */
> > +	if (!dw)
> > +		return -ENODEV;
> > +
> >  	/* Disable eDMA */
> >  	dw_edma_v0_core_off(dw);
> >  
> > -- 
> > 2.35.1
> > 

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

* Re: [PATCH 25/25] PCI: dwc: Add DW eDMA engine support
  2022-03-28 14:15   ` Manivannan Sadhasivam
@ 2022-04-19 20:54     ` Serge Semin
  2022-04-23 14:40       ` Manivannan Sadhasivam
  0 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-04-19 20:54 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Lorenzo Pieralisi, Rob Herring,
	Krzysztof Wilczyński, Alexey Malahov, Pavel Parkhomenko,
	linux-pci, dmaengine, linux-kernel

On Mon, Mar 28, 2022 at 07:45:21PM +0530, Manivannan Sadhasivam wrote:
> On Thu, Mar 24, 2022 at 04:48:36AM +0300, Serge Semin wrote:
> > Since the DW eDMA driver now supports eDMA controllers embedded into the
> > locally accessible DW PCIe Root Ports and End-points, we can use the
> > updated interface to register DW eDMA as DMA engine device if it's
> > available. In order to successfully do that the DW PCIe core driver need
> > to perform some preparations first. First of all it needs to find out the
> > eDMA controller CSRs base address, whether they are accessible over the
> > Port Logic or iATU unrolled space. Afterwards it can try to auto-detect
> > the eDMA controller availability and number of it's read/write channels.
> > If none was found the procedure will just silently halt with no error
> > returned. Secondly the platform is supposed to provide either combined or
> > per-channel IRQ signals. If no valid IRQs set is found the procedure will
> > also halt with no error returned so to be backward compatible with
> > platforms where DW PCIe controllers have eDMA embedded but lack of the
> > IRQs defined for them. Finally before actually probing the eDMA device we
> > need to allocate LLP items buffers. After that the DW eDMA can be
> > registered. If registration is successful the info-message regarding the
> > number of detected Read/Write eDMA channels will be printed to the system
> > log in the same way as it's done for iATU settings.
> > 
> > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > ---
> >  .../pci/controller/dwc/pcie-designware-ep.c   |   4 +
> >  .../pci/controller/dwc/pcie-designware-host.c |  13 +-
> >  drivers/pci/controller/dwc/pcie-designware.c  | 188 ++++++++++++++++++
> >  drivers/pci/controller/dwc/pcie-designware.h  |  23 ++-
> >  4 files changed, 225 insertions(+), 3 deletions(-)
> > 
> > diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > index 23401f17e8f0..b2840d1a5b9a 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > @@ -712,6 +712,10 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> >  
> >  	dw_pcie_iatu_detect(pci);
> >  
> > +	ret = dw_pcie_edma_detect(pci);
> > +	if (ret)
> > +		return ret;
> > +
> >  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
> >  	if (!res)
> >  		return -EINVAL;
> 

> eDMA needs to be removed on error path

So does the EPC memory... The dw_pcie_ep_init() and the code using it
are broken in the cleanup part. Neither the platform drivers nor the
method itself de-allocate the epc memory on any further error. See,
the dw_pcie_ep_exit() function isn't called by any glue driver, while
some of them do have the device remove method implemented. I
am not going to fix the platform drivers (though the devm_add_action()
method could be used for that in a least painful fix) due to lacking
of an EP device to test it out. But since you are asking to revert
the eDMA initialization in case of the EP init failure I'll add the
cleanup-on-error path to the dw_pcie_ep_init() method. But it will be
done in v2 of the "PCI: dwc: Various fixes and cleanups" series.

> 
> > diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> > index 715a13b90e43..048b452ee4f3 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> > @@ -405,14 +405,18 @@ int dw_pcie_host_init(struct pcie_port *pp)
> >  
> >  	dw_pcie_iatu_detect(pci);
> >  
> > -	ret = dw_pcie_setup_rc(pp);
> > +	ret = dw_pcie_edma_detect(pci);
> >  	if (ret)
> >  		goto err_free_msi;
> >  
> > +	ret = dw_pcie_setup_rc(pp);
> > +	if (ret)
> > +		goto err_edma_remove;
> > +
> >  	if (!dw_pcie_link_up(pci) && pci->ops && pci->ops->start_link) {
> >  		ret = pci->ops->start_link(pci);
> >  		if (ret)
> > -			goto err_free_msi;
> > +			goto err_edma_remove;
> >  	}
> >  
> >  	/* Ignore errors, the link may come up later */
> > @@ -430,6 +434,9 @@ int dw_pcie_host_init(struct pcie_port *pp)
> >  	if (pci->ops && pci->ops->stop_link)
> >  		pci->ops->stop_link(pci);
> >  
> > +err_edma_remove:
> > +	dw_pcie_edma_remove(pci);
> > +
> >  err_free_msi:
> >  	if (pp->has_msi_ctrl)
> >  		dw_pcie_free_msi(pp);
> > @@ -452,6 +459,8 @@ void dw_pcie_host_deinit(struct pcie_port *pp)
> >  	if (pci->ops && pci->ops->stop_link)
> >  		pci->ops->stop_link(pci);
> >  
> > +	dw_pcie_edma_remove(pci);
> > +
> >  	if (pp->has_msi_ctrl)
> >  		dw_pcie_free_msi(pp);
> >  
> > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> > index 4a95a7b112e9..dbe39a7ecb71 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware.c
> 
> [...]
> 
> > +int dw_pcie_edma_detect(struct dw_pcie *pci)
> > +{
> > +	int ret;
> > +
> > +	pci->edma.dev = pci->dev;
> > +	if (!pci->edma.ops)
> > +		pci->edma.ops = &dw_pcie_edma_ops;
> > +	pci->edma.flags |= DW_EDMA_CHIP_LOCAL;
> > +

> > +	pci->edma_unroll_enabled = dw_pcie_edma_unroll_enabled(pci);
> 
> Is is possible to continue the unroll path for eDMA if iATU unroll is enabled?

Don't get it. Could you elaborate your question in more details?
Are you talking about using the same flag for both eDMA and iATU
unrolled space? If so then most likely yes. But in that case the
iatu_unroll_enabled flag name and semantics need to be changed.

> 
> > +	if (pci->edma_unroll_enabled && pci->iatu_unroll_enabled) {
> > +		pci->edma.mf = EDMA_MF_EDMA_UNROLL;
> > +		if (pci->atu_base != pci->dbi_base + DEFAULT_DBI_ATU_OFFSET)
> > +			pci->edma.reg_base = pci->atu_base + PCIE_DMA_UNROLL_BASE;
> > +		else
> > +			pci->edma.reg_base = pci->dbi_base + DEFAULT_DBI_DMA_OFFSET;
> 

> This assumption won't work on all platforms. Atleast on our platform, the
> offsets vary. So I'd suggest to try getting the reg_base from DT first and use
> these offsets as a fallback as we do for iATU.

I don't know how the eDMA offset can vary at least concerning the
normal DW PCIe setup. In any case the DW eDMA controller CSRs are
mapped in the same way as the iATU space: CS2=1 CDM=1. They are either
created as an unrolled region mapped into the particular MMIO space
(as a separate MMIO space or as a part of the DBI space), or
accessible over the PL viewports (as a part of the Port Logic CSRs).
Nothing else is described in the hardware manuals. Based on that I
don't see a reason to add one more reg space binding.

> 
> > +	} else {
> > +		pci->edma.mf = EDMA_MF_EDMA_LEGACY;
> > +		pci->edma.reg_base = pci->dbi_base + PCIE_DMA_VIEWPORT_BASE;
> > +	}
> > +
> > +	ret = dw_pcie_edma_detect_channels(pci);
> > +	if (ret) {
> > +		dev_err(pci->dev, "Unexpected NoF eDMA channels found\n");
> > +		return ret;
> > +	}
> > +
> > +	/* Skip any further initialization if no eDMA found */
> 

> Should we introduce a new Kconfig option for enabling eDMA? My concern here is,
> if eDMA is really needed for an usecase and if the platform support is broken
> somehow (DT issues?), then we'll just simply go ahead without probe failure and
> it may break somewhere else.
> 
> And we are returning errors if something wrong happens during eDMA probe. This
> might annoy the existing users who don't care about eDMA but turning those
> errors to debug will affect the real users of eDMA.
> 
> For these reasons, I think it'd be better to probe eDMA only if the Kconfig
> option is enabled (which would be disabled by default). And properly return the
> failure.

I don't see a need in introducing of a new parametrization. Neither
there is a point in dropping the eDMA support on all the platforms for
the sake of some hypothetically malfunction hardware. Regarding the
config, the DW eDMA driver already has one. It's CONFIG_DW_EDMA which
can be used for what you say. Though I need to fix this patch a bit so
the -ENODEV errno returned from the dw_edma_probe() method would be
ignored in the dw_pcie_edma_detect() procedure to support the case of
the disabled DW eDMA driver.

-Sergey

> 
> Thanks,
> Mani

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

* Re: [PATCH 03/25] dma-direct: take dma-ranges/offsets into account in resource mapping
  2022-04-17 22:44     ` Serge Semin
@ 2022-04-20  7:12       ` Christoph Hellwig
  2022-04-20  8:32         ` Serge Semin
  0 siblings, 1 reply; 79+ messages in thread
From: Christoph Hellwig @ 2022-04-20  7:12 UTC (permalink / raw)
  To: Serge Semin
  Cc: Robin Murphy, Serge Semin, Gustavo Pimentel, Vinod Koul,
	Jingoo Han, Bjorn Helgaas, Frank Li, Manivannan Sadhasivam,
	Christoph Hellwig, Marek Szyprowski, Vladimir Murzin,
	Alexey Malahov, Pavel Parkhomenko, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński, linux-pci, dmaengine,
	linux-kernel, iommu

On Mon, Apr 18, 2022 at 01:44:27AM +0300, Serge Semin wrote:
> > but a DMA controller might also want to access something in the MMIO range
> > 0x0-0x7fffffff, of which it still has an identical non-offset view. If a
> > driver was previously using dma_map_resource() for that, it would now start
> > getting DMA_MAPPING_ERROR because the dma_range_map exists but doesn't
> > describe the MMIO region. I agree that in hindsight it's not an ideal
> > situation, but it's how things have ended up, so at this point I'm wary of
> > making potentially-breaking changes.
> 
> Hmm, what if the driver was previously using for instance the
> dma_direct_map_sg() method for it?

dma_map_resource is for mapping MMIO space, and must not be called on
memory in the kernel map.  For dma_map_sg (or all the other dma_map_*
interface except for dma_map_resource), the reverse is true.

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

* Re: [PATCH 03/25] dma-direct: take dma-ranges/offsets into account in resource mapping
  2022-04-20  7:12       ` Christoph Hellwig
@ 2022-04-20  8:32         ` Serge Semin
  2022-04-20  8:47           ` Christoph Hellwig
  0 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-04-20  8:32 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Robin Murphy, Serge Semin, Gustavo Pimentel, Vinod Koul,
	Jingoo Han, Bjorn Helgaas, Frank Li, Manivannan Sadhasivam,
	Marek Szyprowski, Vladimir Murzin, Alexey Malahov,
	Pavel Parkhomenko, Lorenzo Pieralisi, Rob Herring,
	Krzysztof Wilczyński, linux-pci, dmaengine, linux-kernel,
	iommu

On Wed, Apr 20, 2022 at 09:12:17AM +0200, Christoph Hellwig wrote:
> On Mon, Apr 18, 2022 at 01:44:27AM +0300, Serge Semin wrote:
> > > but a DMA controller might also want to access something in the MMIO range
> > > 0x0-0x7fffffff, of which it still has an identical non-offset view. If a
> > > driver was previously using dma_map_resource() for that, it would now start
> > > getting DMA_MAPPING_ERROR because the dma_range_map exists but doesn't
> > > describe the MMIO region. I agree that in hindsight it's not an ideal
> > > situation, but it's how things have ended up, so at this point I'm wary of
> > > making potentially-breaking changes.
> > 
> > Hmm, what if the driver was previously using for instance the
> > dma_direct_map_sg() method for it?
> 

> dma_map_resource is for mapping MMIO space, and must not be called on
> memory in the kernel map.  For dma_map_sg (or all the other dma_map_*
> interface except for dma_map_resource), the reverse is true.

I've got it from the Robin comment. Exactly that part seems very much
confusing to me, because what you say doesn't cohere with the passed
address type. If the passed address belongs to the MMIO space and is a
part of the CPU physical address space, then it is supposed to be
visible by the CPU as is (see the very first diagram in [1]). So the
mapping performed in the dma_map_resource() and dma_map_sg() methods
is supposed to match. Otherwise the spaces you are talking about are
different and as such need to be described by different types. Since
what you are talking about more seem like a DMA address space, then the
dma_map_resource() address needs to have the dma_addr_t type instead
of the phys_addr_t.

BTW here is a brightest example of a system, which contradicts the
MMIO-specific mapping semantics you are talking about (it actually
matches to what we've got except some interconnect implementation
peculiarities):

              +-----+
              | DDR |
              +--+--+
                 |
  +-----+ +------+-------+ +---------+
  | CPU +-+ Interconnect +-+ DEVs... |
  +-----+ +-----^-+------+ +---------+
     dma-ranges-| |-ranges
              +-+-v-+
              | PCI |
              +-----+

See, if I get to map a virtual memory address to be accessible by any
PCIe peripheral device, then the dma_map_sg/dma_map_page/etc
procedures will take the PCIe host controller dma-ranges into account.
It will work as expected and the PCIe devices will see the memory what
I specified. But if I get to pass the physical address of the same
page or a physical address of some device of the DEVs space to the
dma_map_resource(), then the PCIe dma-ranges won't be taken into
account, and the result mapping will be incorrect. That's why the
current dma_map_resource() implementation seems very confusing to me.
As I see it phys_addr_t is the type of the Interconnect address space,
meanwhile dma_addr_t describes the PCIe, DEVs address spaces.

Based on what I said here and in my previous email could you explain
what do I get wrong?

[1] Documentation/core-api/dma-api-howto.rst

-Sergey


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

* Re: [PATCH 03/25] dma-direct: take dma-ranges/offsets into account in resource mapping
  2022-04-20  8:32         ` Serge Semin
@ 2022-04-20  8:47           ` Christoph Hellwig
  2022-04-20  8:55             ` Serge Semin
  0 siblings, 1 reply; 79+ messages in thread
From: Christoph Hellwig @ 2022-04-20  8:47 UTC (permalink / raw)
  To: Serge Semin
  Cc: Christoph Hellwig, Robin Murphy, Serge Semin, Gustavo Pimentel,
	Vinod Koul, Jingoo Han, Bjorn Helgaas, Frank Li,
	Manivannan Sadhasivam, Marek Szyprowski, Vladimir Murzin,
	Alexey Malahov, Pavel Parkhomenko, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński, linux-pci, dmaengine,
	linux-kernel, iommu

I can't really comment on the dma-ranges exlcusion for P2P mappings,
as that predates my involvedment, however:

On Wed, Apr 20, 2022 at 11:32:07AM +0300, Serge Semin wrote:
> See, if I get to map a virtual memory address to be accessible by any
> PCIe peripheral device, then the dma_map_sg/dma_map_page/etc
> procedures will take the PCIe host controller dma-ranges into account.
> It will work as expected and the PCIe devices will see the memory what
> I specified. But if I get to pass the physical address of the same
> page or a physical address of some device of the DEVs space to the
> dma_map_resource(), then the PCIe dma-ranges won't be taken into
> account, and the result mapping will be incorrect. That's why the
> current dma_map_resource() implementation seems very confusing to me.
> As I see it phys_addr_t is the type of the Interconnect address space,
> meanwhile dma_addr_t describes the PCIe, DEVs address spaces.
> 
> Based on what I said here and in my previous email could you explain
> what do I get wrong?

You simply must not use dma_map_resource for normal kernel memory.
So while the exclusion might be somewhat confusing, that confusion
really should not matter for any proper use of the API.

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

* Re: [PATCH 03/25] dma-direct: take dma-ranges/offsets into account in resource mapping
  2022-04-20  8:47           ` Christoph Hellwig
@ 2022-04-20  8:55             ` Serge Semin
  2022-04-21 14:45               ` Christoph Hellwig
  0 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-04-20  8:55 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Robin Murphy, Serge Semin, Gustavo Pimentel, Vinod Koul,
	Jingoo Han, Bjorn Helgaas, Frank Li, Manivannan Sadhasivam,
	Marek Szyprowski, Vladimir Murzin, Alexey Malahov,
	Pavel Parkhomenko, Lorenzo Pieralisi, Rob Herring,
	Krzysztof Wilczyński, linux-pci, dmaengine, linux-kernel,
	iommu

On Wed, Apr 20, 2022 at 10:47:46AM +0200, Christoph Hellwig wrote:
> I can't really comment on the dma-ranges exlcusion for P2P mappings,
> as that predates my involvedment, however:

My example wasn't specific to the PCIe P2P transfers, but about PCIe
devices reaching some platform devices over the system interconnect
bus.

> 
> On Wed, Apr 20, 2022 at 11:32:07AM +0300, Serge Semin wrote:
> > See, if I get to map a virtual memory address to be accessible by any
> > PCIe peripheral device, then the dma_map_sg/dma_map_page/etc
> > procedures will take the PCIe host controller dma-ranges into account.
> > It will work as expected and the PCIe devices will see the memory what
> > I specified. But if I get to pass the physical address of the same
> > page or a physical address of some device of the DEVs space to the
> > dma_map_resource(), then the PCIe dma-ranges won't be taken into
> > account, and the result mapping will be incorrect. That's why the
> > current dma_map_resource() implementation seems very confusing to me.
> > As I see it phys_addr_t is the type of the Interconnect address space,
> > meanwhile dma_addr_t describes the PCIe, DEVs address spaces.
> > 
> > Based on what I said here and in my previous email could you explain
> > what do I get wrong?
> 

> You simply must not use dma_map_resource for normal kernel memory.
> So while the exclusion might be somewhat confusing, that confusion
> really should not matter for any proper use of the API.

What if I get to have a physical address of a platform device and want
have that device being accessed by a PCIe peripheral device? The
dma_map_resource() seemed very much suitable for that. But considering
what you say it isn't.

-Sergey


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

* Re: [PATCH 03/25] dma-direct: take dma-ranges/offsets into account in resource mapping
  2022-04-20  8:55             ` Serge Semin
@ 2022-04-21 14:45               ` Christoph Hellwig
  2022-04-21 17:35                 ` Serge Semin
  0 siblings, 1 reply; 79+ messages in thread
From: Christoph Hellwig @ 2022-04-21 14:45 UTC (permalink / raw)
  To: Serge Semin
  Cc: Christoph Hellwig, Robin Murphy, Serge Semin, Gustavo Pimentel,
	Vinod Koul, Jingoo Han, Bjorn Helgaas, Frank Li,
	Manivannan Sadhasivam, Marek Szyprowski, Vladimir Murzin,
	Alexey Malahov, Pavel Parkhomenko, Lorenzo Pieralisi,
	Rob Herring, Krzysztof Wilczyński, linux-pci, dmaengine,
	linux-kernel, iommu

On Wed, Apr 20, 2022 at 11:55:38AM +0300, Serge Semin wrote:
> On Wed, Apr 20, 2022 at 10:47:46AM +0200, Christoph Hellwig wrote:
> > I can't really comment on the dma-ranges exlcusion for P2P mappings,
> > as that predates my involvedment, however:
> 
> My example wasn't specific to the PCIe P2P transfers, but about PCIe
> devices reaching some platform devices over the system interconnect
> bus.

So strike PCIe, but this our definition of Peer to Peer accesses.

> What if I get to have a physical address of a platform device and want
> have that device being accessed by a PCIe peripheral device? The
> dma_map_resource() seemed very much suitable for that. But considering
> what you say it isn't.

dma_map_resource is the right thing for that.  But the physical address
of MMIO ranges in the platform device should not have struct pages
allocated for it, and thus the other dma_map_* APIs should not work on
it to start with.

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

* Re: [PATCH 03/25] dma-direct: take dma-ranges/offsets into account in resource mapping
  2022-04-21 14:45               ` Christoph Hellwig
@ 2022-04-21 17:35                 ` Serge Semin
  2022-04-21 20:51                   ` Robin Murphy
  0 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-04-21 17:35 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Robin Murphy, Serge Semin, Gustavo Pimentel, Vinod Koul,
	Jingoo Han, Bjorn Helgaas, Frank Li, Manivannan Sadhasivam,
	Marek Szyprowski, Vladimir Murzin, Alexey Malahov,
	Pavel Parkhomenko, Lorenzo Pieralisi, Rob Herring,
	Krzysztof Wilczyński, linux-pci, dmaengine, linux-kernel,
	iommu

On Thu, Apr 21, 2022 at 04:45:36PM +0200, Christoph Hellwig wrote:
> On Wed, Apr 20, 2022 at 11:55:38AM +0300, Serge Semin wrote:
> > On Wed, Apr 20, 2022 at 10:47:46AM +0200, Christoph Hellwig wrote:
> > > I can't really comment on the dma-ranges exlcusion for P2P mappings,
> > > as that predates my involvedment, however:
> > 
> > My example wasn't specific to the PCIe P2P transfers, but about PCIe
> > devices reaching some platform devices over the system interconnect
> > bus.
> 
> So strike PCIe, but this our definition of Peer to Peer accesses.
> 
> > What if I get to have a physical address of a platform device and want
> > have that device being accessed by a PCIe peripheral device? The
> > dma_map_resource() seemed very much suitable for that. But considering
> > what you say it isn't.
> 

> dma_map_resource is the right thing for that.  But the physical address
> of MMIO ranges in the platform device should not have struct pages
> allocated for it, and thus the other dma_map_* APIs should not work on
> it to start with.

The problem is that the dma_map_resource() won't work for that, but
presumably the dma_map_sg()-like methods will (after some hacking with
the phys address, but anyway). Consider the system diagram in my
previous email. Here is what I would do to initialize a DMA
transaction between a platform device and a PCIe peripheral device:

1) struct resource *rsc = platform_get_resource(plat_dev, IORESOURCE_MEM, 0);

2) dma_addr_t dar = dma_map_resource(&pci_dev->dev, rsc->start, rsc->end - rsc->start + 1,
                                      DMA_FROM_DEVICE, 0);

3) dma_addr_t sar;
   void *tmp = dma_alloc_coherent(&pci_dev->dev, PAGE_SIZE, &sar, GFP_KERNEL);
   memset(tmp, 0xaa, PAGE_SIZE);

4) PCIe device: DMA.DAR=dar, DMA.SAR=sar. RUN.

If there is no dma-ranges specified in the PCIe Host controller
DT-node, the PCIe peripheral devices will see the rest of the system
memory as is (no offsets and remappings). But if there is dma-ranges
with some specific system settings it may affect the PCIe MRd/MWr TLPs
address translation including the addresses targeted to the MMIO
space. In that case the mapping performed on step 2) will return a
wrong DMA-address since the corresponding dma_direct_map_resource()
just returns the passed physical address missing the
'pci_dev->dma_range_map'-based mapping performed in
translate_phys_to_dma().

Note the mapping on step 3) works correctly because it calls the
translate_phys_to_dma() of the direct DMA interface thus taking the
PCie dma-ranges into account.

To sum up as I see it either restricting dma_map_resource() to map
just the intra-bus addresses was wrong or there must be some
additional mapping infrastructure for the denoted systems. Though I
don't see a way the dma_map_resource() could be fixed to be suitable
for each considered cases.

-Sergey
   
map the platforms


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

* Re: [PATCH 03/25] dma-direct: take dma-ranges/offsets into account in resource mapping
  2022-04-21 17:35                 ` Serge Semin
@ 2022-04-21 20:51                   ` Robin Murphy
  2022-04-24 21:46                     ` Serge Semin
  0 siblings, 1 reply; 79+ messages in thread
From: Robin Murphy @ 2022-04-21 20:51 UTC (permalink / raw)
  To: Serge Semin, Christoph Hellwig
  Cc: Rob Herring, Vladimir Murzin, Krzysztof Wilczyński,
	linux-pci, Gustavo Pimentel, Manivannan Sadhasivam, Frank Li,
	linux-kernel, iommu, Alexey Malahov, Serge Semin, dmaengine,
	Vinod Koul, Pavel Parkhomenko, Jingoo Han, Bjorn Helgaas

On 2022-04-21 18:35, Serge Semin wrote:
> On Thu, Apr 21, 2022 at 04:45:36PM +0200, Christoph Hellwig wrote:
>> On Wed, Apr 20, 2022 at 11:55:38AM +0300, Serge Semin wrote:
>>> On Wed, Apr 20, 2022 at 10:47:46AM +0200, Christoph Hellwig wrote:
>>>> I can't really comment on the dma-ranges exlcusion for P2P mappings,
>>>> as that predates my involvedment, however:
>>>
>>> My example wasn't specific to the PCIe P2P transfers, but about PCIe
>>> devices reaching some platform devices over the system interconnect
>>> bus.
>>
>> So strike PCIe, but this our definition of Peer to Peer accesses.
>>
>>> What if I get to have a physical address of a platform device and want
>>> have that device being accessed by a PCIe peripheral device? The
>>> dma_map_resource() seemed very much suitable for that. But considering
>>> what you say it isn't.
>>
> 
>> dma_map_resource is the right thing for that.  But the physical address
>> of MMIO ranges in the platform device should not have struct pages
>> allocated for it, and thus the other dma_map_* APIs should not work on
>> it to start with.
> 
> The problem is that the dma_map_resource() won't work for that, but
> presumably the dma_map_sg()-like methods will (after some hacking with
> the phys address, but anyway). Consider the system diagram in my
> previous email. Here is what I would do to initialize a DMA
> transaction between a platform device and a PCIe peripheral device:
> 
> 1) struct resource *rsc = platform_get_resource(plat_dev, IORESOURCE_MEM, 0);
> 
> 2) dma_addr_t dar = dma_map_resource(&pci_dev->dev, rsc->start, rsc->end - rsc->start + 1,
>                                        DMA_FROM_DEVICE, 0);
> 
> 3) dma_addr_t sar;
>     void *tmp = dma_alloc_coherent(&pci_dev->dev, PAGE_SIZE, &sar, GFP_KERNEL);
>     memset(tmp, 0xaa, PAGE_SIZE);
> 
> 4) PCIe device: DMA.DAR=dar, DMA.SAR=sar. RUN.
> 
> If there is no dma-ranges specified in the PCIe Host controller
> DT-node, the PCIe peripheral devices will see the rest of the system
> memory as is (no offsets and remappings). But if there is dma-ranges
> with some specific system settings it may affect the PCIe MRd/MWr TLPs
> address translation including the addresses targeted to the MMIO
> space. In that case the mapping performed on step 2) will return a
> wrong DMA-address since the corresponding dma_direct_map_resource()
> just returns the passed physical address missing the
> 'pci_dev->dma_range_map'-based mapping performed in
> translate_phys_to_dma().
> 
> Note the mapping on step 3) works correctly because it calls the
> translate_phys_to_dma() of the direct DMA interface thus taking the
> PCie dma-ranges into account.
> 
> To sum up as I see it either restricting dma_map_resource() to map
> just the intra-bus addresses was wrong or there must be some
> additional mapping infrastructure for the denoted systems. Though I
> don't see a way the dma_map_resource() could be fixed to be suitable
> for each considered cases.

FWIW the current semantics of dma_map_resource() are basically just to 
insert IOMMU awareness where dmaengine drivers were previously just 
casting phys_addr_t to dma_addr_t (or u32, or whatever else they put 
into their descriptor/register/etc.) IIRC there was a bit of a question 
whether it really belonged in the DMA API at all, since it's not really 
a "DMA" operation in the conventional sense, and convenience was the 
only real deciding argument. The relevant drivers at the time were not 
taking dma_pfn_offset into account when consuming physical addresses 
directly, so the new API didn't either.

That's just how things got to where they are today. Once again, I'm not 
saying that what we have now is necessarily right, or that your change 
is necessarily wrong, I just really want to understand specifically 
*why* you need to make it, so we can evaluate the risk of possible 
breakage either way. Theoretical "if"s aren't really enough.

Robin.

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

* Re: [PATCH 25/25] PCI: dwc: Add DW eDMA engine support
  2022-04-19 20:54     ` Serge Semin
@ 2022-04-23 14:40       ` Manivannan Sadhasivam
  2022-04-25  5:22         ` Manivannan Sadhasivam
  2022-04-28 14:05         ` Serge Semin
  0 siblings, 2 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-04-23 14:40 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Lorenzo Pieralisi, Rob Herring,
	Krzysztof Wilczyński, Alexey Malahov, Pavel Parkhomenko,
	linux-pci, dmaengine, linux-kernel

On Tue, Apr 19, 2022 at 11:54:03PM +0300, Serge Semin wrote:
> On Mon, Mar 28, 2022 at 07:45:21PM +0530, Manivannan Sadhasivam wrote:
> > On Thu, Mar 24, 2022 at 04:48:36AM +0300, Serge Semin wrote:
> > > Since the DW eDMA driver now supports eDMA controllers embedded into the
> > > locally accessible DW PCIe Root Ports and End-points, we can use the
> > > updated interface to register DW eDMA as DMA engine device if it's
> > > available. In order to successfully do that the DW PCIe core driver need
> > > to perform some preparations first. First of all it needs to find out the
> > > eDMA controller CSRs base address, whether they are accessible over the
> > > Port Logic or iATU unrolled space. Afterwards it can try to auto-detect
> > > the eDMA controller availability and number of it's read/write channels.
> > > If none was found the procedure will just silently halt with no error
> > > returned. Secondly the platform is supposed to provide either combined or
> > > per-channel IRQ signals. If no valid IRQs set is found the procedure will
> > > also halt with no error returned so to be backward compatible with
> > > platforms where DW PCIe controllers have eDMA embedded but lack of the
> > > IRQs defined for them. Finally before actually probing the eDMA device we
> > > need to allocate LLP items buffers. After that the DW eDMA can be
> > > registered. If registration is successful the info-message regarding the
> > > number of detected Read/Write eDMA channels will be printed to the system
> > > log in the same way as it's done for iATU settings.
> > > 
> > > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > > ---
> > >  .../pci/controller/dwc/pcie-designware-ep.c   |   4 +
> > >  .../pci/controller/dwc/pcie-designware-host.c |  13 +-
> > >  drivers/pci/controller/dwc/pcie-designware.c  | 188 ++++++++++++++++++
> > >  drivers/pci/controller/dwc/pcie-designware.h  |  23 ++-
> > >  4 files changed, 225 insertions(+), 3 deletions(-)
> > > 
> > > diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > index 23401f17e8f0..b2840d1a5b9a 100644
> > > --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > @@ -712,6 +712,10 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> > >  
> > >  	dw_pcie_iatu_detect(pci);
> > >  
> > > +	ret = dw_pcie_edma_detect(pci);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > >  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
> > >  	if (!res)
> > >  		return -EINVAL;
> > 
> 
> > eDMA needs to be removed on error path
> 
> So does the EPC memory... The dw_pcie_ep_init() and the code using it
> are broken in the cleanup part. Neither the platform drivers nor the
> method itself de-allocate the epc memory on any further error. See,

Right.

> the dw_pcie_ep_exit() function isn't called by any glue driver, while
> some of them do have the device remove method implemented. I
> am not going to fix the platform drivers (though the devm_add_action()
> method could be used for that in a least painful fix) due to lacking
> of an EP device to test it out. But since you are asking to revert
> the eDMA initialization in case of the EP init failure I'll add the
> cleanup-on-error path to the dw_pcie_ep_init() method. But it will be
> done in v2 of the "PCI: dwc: Various fixes and cleanups" series.
> 

That's fine, thanks.

> > 
> > > diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> > > index 715a13b90e43..048b452ee4f3 100644
> > > --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> > > +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> > > @@ -405,14 +405,18 @@ int dw_pcie_host_init(struct pcie_port *pp)
> > >  
> > >  	dw_pcie_iatu_detect(pci);
> > >  
> > > -	ret = dw_pcie_setup_rc(pp);
> > > +	ret = dw_pcie_edma_detect(pci);
> > >  	if (ret)
> > >  		goto err_free_msi;
> > >  
> > > +	ret = dw_pcie_setup_rc(pp);
> > > +	if (ret)
> > > +		goto err_edma_remove;
> > > +
> > >  	if (!dw_pcie_link_up(pci) && pci->ops && pci->ops->start_link) {
> > >  		ret = pci->ops->start_link(pci);
> > >  		if (ret)
> > > -			goto err_free_msi;
> > > +			goto err_edma_remove;
> > >  	}
> > >  
> > >  	/* Ignore errors, the link may come up later */
> > > @@ -430,6 +434,9 @@ int dw_pcie_host_init(struct pcie_port *pp)
> > >  	if (pci->ops && pci->ops->stop_link)
> > >  		pci->ops->stop_link(pci);
> > >  
> > > +err_edma_remove:
> > > +	dw_pcie_edma_remove(pci);
> > > +
> > >  err_free_msi:
> > >  	if (pp->has_msi_ctrl)
> > >  		dw_pcie_free_msi(pp);
> > > @@ -452,6 +459,8 @@ void dw_pcie_host_deinit(struct pcie_port *pp)
> > >  	if (pci->ops && pci->ops->stop_link)
> > >  		pci->ops->stop_link(pci);
> > >  
> > > +	dw_pcie_edma_remove(pci);
> > > +
> > >  	if (pp->has_msi_ctrl)
> > >  		dw_pcie_free_msi(pp);
> > >  
> > > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> > > index 4a95a7b112e9..dbe39a7ecb71 100644
> > > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > > +++ b/drivers/pci/controller/dwc/pcie-designware.c
> > 
> > [...]
> > 
> > > +int dw_pcie_edma_detect(struct dw_pcie *pci)
> > > +{
> > > +	int ret;
> > > +
> > > +	pci->edma.dev = pci->dev;
> > > +	if (!pci->edma.ops)
> > > +		pci->edma.ops = &dw_pcie_edma_ops;
> > > +	pci->edma.flags |= DW_EDMA_CHIP_LOCAL;
> > > +
> 
> > > +	pci->edma_unroll_enabled = dw_pcie_edma_unroll_enabled(pci);
> > 
> > Is is possible to continue the unroll path for eDMA if iATU unroll is enabled?
> 
> Don't get it. Could you elaborate your question in more details?
> Are you talking about using the same flag for both eDMA and iATU
> unrolled space? If so then most likely yes. But in that case the
> iatu_unroll_enabled flag name and semantics need to be changed.
> 

If iATU has unroll enabled then I think we can assume that edma will also be
the same. So I was wondering if we could just depend on iatu_unroll_enabled
here.

> > 
> > > +	if (pci->edma_unroll_enabled && pci->iatu_unroll_enabled) {
> > > +		pci->edma.mf = EDMA_MF_EDMA_UNROLL;
> > > +		if (pci->atu_base != pci->dbi_base + DEFAULT_DBI_ATU_OFFSET)
> > > +			pci->edma.reg_base = pci->atu_base + PCIE_DMA_UNROLL_BASE;
> > > +		else
> > > +			pci->edma.reg_base = pci->dbi_base + DEFAULT_DBI_DMA_OFFSET;
> > 
> 
> > This assumption won't work on all platforms. Atleast on our platform, the
> > offsets vary. So I'd suggest to try getting the reg_base from DT first and use
> > these offsets as a fallback as we do for iATU.
> 
> I don't know how the eDMA offset can vary at least concerning the
> normal DW PCIe setup. In any case the DW eDMA controller CSRs are
> mapped in the same way as the iATU space: CS2=1 CDM=1. They are either
> created as an unrolled region mapped into the particular MMIO space
> (as a separate MMIO space or as a part of the DBI space), or
> accessible over the PL viewports (as a part of the Port Logic CSRs).
> Nothing else is described in the hardware manuals. Based on that I
> don't see a reason to add one more reg space binding.
> 

This is not true. Vendors can customize the iATU location inside DBI region
for unroll too. That's one of the reason why dw_pcie_iatu_detect() works on
qcom platforms as it tries to get iatu address from DT first and then falls
back to the default offset if not found.

So please define an additional DT region for edma.

> > 
> > > +	} else {
> > > +		pci->edma.mf = EDMA_MF_EDMA_LEGACY;
> > > +		pci->edma.reg_base = pci->dbi_base + PCIE_DMA_VIEWPORT_BASE;
> > > +	}
> > > +
> > > +	ret = dw_pcie_edma_detect_channels(pci);
> > > +	if (ret) {
> > > +		dev_err(pci->dev, "Unexpected NoF eDMA channels found\n");
> > > +		return ret;
> > > +	}
> > > +
> > > +	/* Skip any further initialization if no eDMA found */
> > 
> 
> > Should we introduce a new Kconfig option for enabling eDMA? My concern here is,
> > if eDMA is really needed for an usecase and if the platform support is broken
> > somehow (DT issues?), then we'll just simply go ahead without probe failure and
> > it may break somewhere else.
> > 
> > And we are returning errors if something wrong happens during eDMA probe. This
> > might annoy the existing users who don't care about eDMA but turning those
> > errors to debug will affect the real users of eDMA.
> > 
> > For these reasons, I think it'd be better to probe eDMA only if the Kconfig
> > option is enabled (which would be disabled by default). And properly return the
> > failure.
> 
> I don't see a need in introducing of a new parametrization. Neither
> there is a point in dropping the eDMA support on all the platforms for
> the sake of some hypothetically malfunction hardware.

I'm not talking about "hypothetically malfunction hardware" but real customized
ones like all Qcom platforms supporting PCIe. As I said in my previous comment,
the default eDMA offset won't work on Qcom platforms. So if this driver tries
to access the registers based on the default offset, it may result in SMMU
errors. The edma region needs to be defined in DT for probing edma correctly.

But even if we add dt support for edma and probe edma unconditionally, we'd be
breaking the dts compatibility with older ones that don't define it.

> Regarding the
> config, the DW eDMA driver already has one. It's CONFIG_DW_EDMA which
> can be used for what you say. Though I need to fix this patch a bit so
> the -ENODEV errno returned from the dw_edma_probe() method would be
> ignored in the dw_pcie_edma_detect() procedure to support the case of
> the disabled DW eDMA driver.
> 

Please do so.

Thanks,
Mani

> -Sergey
> 
> > 
> > Thanks,
> > Mani

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

* Re: [PATCH 24/25] dmaengine: dw-edma: Skip cleanup procedure if no private data found
  2022-04-18 13:48     ` Serge Semin
@ 2022-04-23 14:45       ` Manivannan Sadhasivam
  0 siblings, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-04-23 14:45 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Alexey Malahov, Pavel Parkhomenko,
	Lorenzo Pieralisi, Rob Herring, Krzysztof Wilczyński,
	linux-pci, dmaengine, linux-kernel

On Mon, Apr 18, 2022 at 04:48:33PM +0300, Serge Semin wrote:
> On Fri, Mar 25, 2022 at 11:45:03PM +0530, Manivannan Sadhasivam wrote:
> > On Thu, Mar 24, 2022 at 04:48:35AM +0300, Serge Semin wrote:
> > > DW eDMA driver private data is preserved in the passed DW eDMA chip info
> > > structure. If either probe procedure failed or for some reason the passed
> > > info object doesn't have private data pointer initialized we need to halt
> > > the DMA device cleanup procedure in order to prevent possible system
> > > crashes.
> > > 
> > 
> 
> > How come remove() could happen when probe() failed? If you hit this issue then
> > something else is utterly going wrong.
> 
> It fully depends on the DW eDMA client driver implementation, which
> can't and in general shouldn't be guessed. But what must be done in
> the DW eDMA driver is a protection against the invalid data being
> passed to the exported API methods. That wrong situation must be
> detected and handled in the API user code. It's much easier to do by
> having an error code returned from the dw_edma_remove() method than
> catching random system crashes.
> 

Even though I don't see any practical issue, I'm fine with this.

Thanks,
Mani

> -Sergey
> 
> > 
> > Thanks,
> > Mani
> > 
> > > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > > ---
> > >  drivers/dma/dw-edma/dw-edma-core.c | 4 ++++
> > >  1 file changed, 4 insertions(+)
> > > 
> > > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > > index ca5cd7c99571..b932682a8ba8 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > @@ -1030,6 +1030,10 @@ int dw_edma_remove(struct dw_edma_chip *chip)
> > >  	struct dw_edma *dw = chip->dw;
> > >  	int i;
> > >  
> > > +	/* Skip removal if no private data found */
> > > +	if (!dw)
> > > +		return -ENODEV;
> > > +
> > >  	/* Disable eDMA */
> > >  	dw_edma_v0_core_off(dw);
> > >  
> > > -- 
> > > 2.35.1
> > > 

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

* Re: [PATCH 03/25] dma-direct: take dma-ranges/offsets into account in resource mapping
  2022-04-21 20:51                   ` Robin Murphy
@ 2022-04-24 21:46                     ` Serge Semin
  0 siblings, 0 replies; 79+ messages in thread
From: Serge Semin @ 2022-04-24 21:46 UTC (permalink / raw)
  To: Robin Murphy
  Cc: Christoph Hellwig, Rob Herring, Vladimir Murzin,
	Krzysztof Wilczyński, linux-pci, Gustavo Pimentel,
	Manivannan Sadhasivam, Frank Li, linux-kernel, iommu,
	Alexey Malahov, Serge Semin, dmaengine, Vinod Koul,
	Pavel Parkhomenko, Jingoo Han, Bjorn Helgaas

On Thu, Apr 21, 2022 at 09:51:31PM +0100, Robin Murphy wrote:
> On 2022-04-21 18:35, Serge Semin wrote:
> > On Thu, Apr 21, 2022 at 04:45:36PM +0200, Christoph Hellwig wrote:
> > > On Wed, Apr 20, 2022 at 11:55:38AM +0300, Serge Semin wrote:
> > > > On Wed, Apr 20, 2022 at 10:47:46AM +0200, Christoph Hellwig wrote:
> > > > > I can't really comment on the dma-ranges exlcusion for P2P mappings,
> > > > > as that predates my involvedment, however:
> > > > 
> > > > My example wasn't specific to the PCIe P2P transfers, but about PCIe
> > > > devices reaching some platform devices over the system interconnect
> > > > bus.
> > > 
> > > So strike PCIe, but this our definition of Peer to Peer accesses.
> > > 
> > > > What if I get to have a physical address of a platform device and want
> > > > have that device being accessed by a PCIe peripheral device? The
> > > > dma_map_resource() seemed very much suitable for that. But considering
> > > > what you say it isn't.
> > > 
> > 
> > > dma_map_resource is the right thing for that.  But the physical address
> > > of MMIO ranges in the platform device should not have struct pages
> > > allocated for it, and thus the other dma_map_* APIs should not work on
> > > it to start with.
> > 
> > The problem is that the dma_map_resource() won't work for that, but
> > presumably the dma_map_sg()-like methods will (after some hacking with
> > the phys address, but anyway). Consider the system diagram in my
> > previous email. Here is what I would do to initialize a DMA
> > transaction between a platform device and a PCIe peripheral device:
> > 
> > 1) struct resource *rsc = platform_get_resource(plat_dev, IORESOURCE_MEM, 0);
> > 
> > 2) dma_addr_t dar = dma_map_resource(&pci_dev->dev, rsc->start, rsc->end - rsc->start + 1,
> >                                        DMA_FROM_DEVICE, 0);
> > 
> > 3) dma_addr_t sar;
> >     void *tmp = dma_alloc_coherent(&pci_dev->dev, PAGE_SIZE, &sar, GFP_KERNEL);
> >     memset(tmp, 0xaa, PAGE_SIZE);
> > 
> > 4) PCIe device: DMA.DAR=dar, DMA.SAR=sar. RUN.
> > 
> > If there is no dma-ranges specified in the PCIe Host controller
> > DT-node, the PCIe peripheral devices will see the rest of the system
> > memory as is (no offsets and remappings). But if there is dma-ranges
> > with some specific system settings it may affect the PCIe MRd/MWr TLPs
> > address translation including the addresses targeted to the MMIO
> > space. In that case the mapping performed on step 2) will return a
> > wrong DMA-address since the corresponding dma_direct_map_resource()
> > just returns the passed physical address missing the
> > 'pci_dev->dma_range_map'-based mapping performed in
> > translate_phys_to_dma().
> > 
> > Note the mapping on step 3) works correctly because it calls the
> > translate_phys_to_dma() of the direct DMA interface thus taking the
> > PCie dma-ranges into account.
> > 
> > To sum up as I see it either restricting dma_map_resource() to map
> > just the intra-bus addresses was wrong or there must be some
> > additional mapping infrastructure for the denoted systems. Though I
> > don't see a way the dma_map_resource() could be fixed to be suitable
> > for each considered cases.
> 

> FWIW the current semantics of dma_map_resource() are basically just to
> insert IOMMU awareness where dmaengine drivers were previously just casting
> phys_addr_t to dma_addr_t (or u32, or whatever else they put into their
> descriptor/register/etc.) IIRC there was a bit of a question whether it
> really belonged in the DMA API at all, since it's not really a "DMA"
> operation in the conventional sense, and convenience was the only real
> deciding argument. The relevant drivers at the time were not taking
> dma_pfn_offset into account when consuming physical addresses directly, so
> the new API didn't either.
> 
> That's just how things got to where they are today. 

I see. Thanks for the clarification. Right, IOMMU is the only reason
to have the current dma_map_resource() implementation.

> Once again, I'm not
> saying that what we have now is necessarily right, or that your change is
> necessarily wrong, I just really want to understand specifically *why* you
> need to make it, so we can evaluate the risk of possible breakage either
> way. Theoretical "if"s aren't really enough.

As I already said our SoC has the next structure (obviously the
diagram is very simplified, but the gist is the same):
              +-----+
              | DDR |
              +--+--+
                 |
  +-----+ +------+-------+ +---------+
  | CPU +-+ Interconnect +-+ DEVs... |
  +-----+ +-----^-+------+ +---------+
     dma-ranges-| |-ranges
              +-+-v-+
              | PCI |
              +-----+
The PCIe peripheral devices are connected to the rest of the system
via the DW PCIe Host controller. If the controller has the inbound
iATU configured to re-map the system memory (RAM, IOMEM) in a
non-one-to-one way (using the dma-ranges DT property of the PCIe host
controller), then all the PCIe bus MRd/MWr TLP addresses will be
accordingly translated on a way to all the connected to the
interconnect slave devices including the MMIO devices. The kernel DMA
API at this moment provides the only methods to get the PCIe-bus
visible RAM addresses, while the physical addresses (for instance of
the MMIO devices) can't be correctly translated for such case. I
thought that dma_map_resource() could do the trick, but it turned out
it didn't get the dma-ranges mapping into account.

To be fully honest currently we don't really have any platform which
would have had the strong requirement of doing DMA from the PCIe
peripheral devices to the platform devices. But since the PCIe bus is
the extendable bus (cold and hot pluggable) then such requirement may
arise in the practice for instance on a platform with the PCIe NTB
device attached to the PCIe bus and configured to access the system
MMIO devices via the bridge. That part I find potentially problematic
seeing the practical usecase is unsupported just due to the incomplete
API. Moreover the dma_direct_map_resource() method semantic being
different from the rest of the direct DMA mapping methods doesn't seem
right from the usability point of view. Finally as you can see having
the dma_direct_map_resource() defined as MMIO-specific doesn't
mean that the dma_pfn_offset-based mapping isn't supposed to be taken
into account.

-Sergey

> 
> Robin.

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

* Re: [PATCH 25/25] PCI: dwc: Add DW eDMA engine support
  2022-04-23 14:40       ` Manivannan Sadhasivam
@ 2022-04-25  5:22         ` Manivannan Sadhasivam
  2022-04-28 14:05         ` Serge Semin
  1 sibling, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-04-25  5:22 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Lorenzo Pieralisi, Rob Herring,
	Krzysztof Wilczyński, Alexey Malahov, Pavel Parkhomenko,
	linux-pci, dmaengine, linux-kernel

On Sat, Apr 23, 2022 at 08:10:55PM +0530, Manivannan Sadhasivam wrote:
> On Tue, Apr 19, 2022 at 11:54:03PM +0300, Serge Semin wrote:
> > On Mon, Mar 28, 2022 at 07:45:21PM +0530, Manivannan Sadhasivam wrote:
> > > On Thu, Mar 24, 2022 at 04:48:36AM +0300, Serge Semin wrote:
> > > > Since the DW eDMA driver now supports eDMA controllers embedded into the
> > > > locally accessible DW PCIe Root Ports and End-points, we can use the
> > > > updated interface to register DW eDMA as DMA engine device if it's
> > > > available. In order to successfully do that the DW PCIe core driver need
> > > > to perform some preparations first. First of all it needs to find out the
> > > > eDMA controller CSRs base address, whether they are accessible over the
> > > > Port Logic or iATU unrolled space. Afterwards it can try to auto-detect
> > > > the eDMA controller availability and number of it's read/write channels.
> > > > If none was found the procedure will just silently halt with no error
> > > > returned. Secondly the platform is supposed to provide either combined or
> > > > per-channel IRQ signals. If no valid IRQs set is found the procedure will
> > > > also halt with no error returned so to be backward compatible with
> > > > platforms where DW PCIe controllers have eDMA embedded but lack of the
> > > > IRQs defined for them. Finally before actually probing the eDMA device we
> > > > need to allocate LLP items buffers. After that the DW eDMA can be
> > > > registered. If registration is successful the info-message regarding the
> > > > number of detected Read/Write eDMA channels will be printed to the system
> > > > log in the same way as it's done for iATU settings.
> > > > 
> > > > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > > > ---
> > > >  .../pci/controller/dwc/pcie-designware-ep.c   |   4 +
> > > >  .../pci/controller/dwc/pcie-designware-host.c |  13 +-
> > > >  drivers/pci/controller/dwc/pcie-designware.c  | 188 ++++++++++++++++++
> > > >  drivers/pci/controller/dwc/pcie-designware.h  |  23 ++-
> > > >  4 files changed, 225 insertions(+), 3 deletions(-)
> > > > 

[...]

> > > > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> > > > index 4a95a7b112e9..dbe39a7ecb71 100644
> > > > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > > > +++ b/drivers/pci/controller/dwc/pcie-designware.c

[...]

> > > Should we introduce a new Kconfig option for enabling eDMA? My concern here is,
> > > if eDMA is really needed for an usecase and if the platform support is broken
> > > somehow (DT issues?), then we'll just simply go ahead without probe failure and
> > > it may break somewhere else.
> > > 
> > > And we are returning errors if something wrong happens during eDMA probe. This
> > > might annoy the existing users who don't care about eDMA but turning those
> > > errors to debug will affect the real users of eDMA.
> > > 
> > > For these reasons, I think it'd be better to probe eDMA only if the Kconfig
> > > option is enabled (which would be disabled by default). And properly return the
> > > failure.
> > 
> > I don't see a need in introducing of a new parametrization. Neither
> > there is a point in dropping the eDMA support on all the platforms for
> > the sake of some hypothetically malfunction hardware.
> 
> I'm not talking about "hypothetically malfunction hardware" but real customized
> ones like all Qcom platforms supporting PCIe.

Correction: It is not "all Qcom platforms" but some like SM8250, SM8450 etc...

Thanks,
Mani

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

* Re: [PATCH 25/25] PCI: dwc: Add DW eDMA engine support
  2022-04-23 14:40       ` Manivannan Sadhasivam
  2022-04-25  5:22         ` Manivannan Sadhasivam
@ 2022-04-28 14:05         ` Serge Semin
  2022-04-28 17:09           ` Manivannan Sadhasivam
  1 sibling, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-04-28 14:05 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Lorenzo Pieralisi, Rob Herring,
	Krzysztof Wilczyński, Alexey Malahov, Pavel Parkhomenko,
	linux-pci, dmaengine, linux-kernel

On Sat, Apr 23, 2022 at 08:10:55PM +0530, Manivannan Sadhasivam wrote:
> On Tue, Apr 19, 2022 at 11:54:03PM +0300, Serge Semin wrote:
> > On Mon, Mar 28, 2022 at 07:45:21PM +0530, Manivannan Sadhasivam wrote:
> > > On Thu, Mar 24, 2022 at 04:48:36AM +0300, Serge Semin wrote:
> > > > Since the DW eDMA driver now supports eDMA controllers embedded into the
> > > > locally accessible DW PCIe Root Ports and End-points, we can use the
> > > > updated interface to register DW eDMA as DMA engine device if it's
> > > > available. In order to successfully do that the DW PCIe core driver need
> > > > to perform some preparations first. First of all it needs to find out the
> > > > eDMA controller CSRs base address, whether they are accessible over the
> > > > Port Logic or iATU unrolled space. Afterwards it can try to auto-detect
> > > > the eDMA controller availability and number of it's read/write channels.
> > > > If none was found the procedure will just silently halt with no error
> > > > returned. Secondly the platform is supposed to provide either combined or
> > > > per-channel IRQ signals. If no valid IRQs set is found the procedure will
> > > > also halt with no error returned so to be backward compatible with
> > > > platforms where DW PCIe controllers have eDMA embedded but lack of the
> > > > IRQs defined for them. Finally before actually probing the eDMA device we
> > > > need to allocate LLP items buffers. After that the DW eDMA can be
> > > > registered. If registration is successful the info-message regarding the
> > > > number of detected Read/Write eDMA channels will be printed to the system
> > > > log in the same way as it's done for iATU settings.
> > > > 
> > > > Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
> > > > ---
> > > >  .../pci/controller/dwc/pcie-designware-ep.c   |   4 +
> > > >  .../pci/controller/dwc/pcie-designware-host.c |  13 +-
> > > >  drivers/pci/controller/dwc/pcie-designware.c  | 188 ++++++++++++++++++
> > > >  drivers/pci/controller/dwc/pcie-designware.h  |  23 ++-
> > > >  4 files changed, 225 insertions(+), 3 deletions(-)
> > > > 
> > > > diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > > index 23401f17e8f0..b2840d1a5b9a 100644
> > > > --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > > +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > > @@ -712,6 +712,10 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
> > > >  
> > > >  	dw_pcie_iatu_detect(pci);
> > > >  
> > > > +	ret = dw_pcie_edma_detect(pci);
> > > > +	if (ret)
> > > > +		return ret;
> > > > +
> > > >  	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
> > > >  	if (!res)
> > > >  		return -EINVAL;
> > > 
> > 
> > > eDMA needs to be removed on error path
> > 
> > So does the EPC memory... The dw_pcie_ep_init() and the code using it
> > are broken in the cleanup part. Neither the platform drivers nor the
> > method itself de-allocate the epc memory on any further error. See,
> 
> Right.
> 
> > the dw_pcie_ep_exit() function isn't called by any glue driver, while
> > some of them do have the device remove method implemented. I
> > am not going to fix the platform drivers (though the devm_add_action()
> > method could be used for that in a least painful fix) due to lacking
> > of an EP device to test it out. But since you are asking to revert
> > the eDMA initialization in case of the EP init failure I'll add the
> > cleanup-on-error path to the dw_pcie_ep_init() method. But it will be
> > done in v2 of the "PCI: dwc: Various fixes and cleanups" series.
> > 
> 
> That's fine, thanks.
> 
> > > 
> > > > diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> > > > index 715a13b90e43..048b452ee4f3 100644
> > > > --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> > > > +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> > > > @@ -405,14 +405,18 @@ int dw_pcie_host_init(struct pcie_port *pp)
> > > >  
> > > >  	dw_pcie_iatu_detect(pci);
> > > >  
> > > > -	ret = dw_pcie_setup_rc(pp);
> > > > +	ret = dw_pcie_edma_detect(pci);
> > > >  	if (ret)
> > > >  		goto err_free_msi;
> > > >  
> > > > +	ret = dw_pcie_setup_rc(pp);
> > > > +	if (ret)
> > > > +		goto err_edma_remove;
> > > > +
> > > >  	if (!dw_pcie_link_up(pci) && pci->ops && pci->ops->start_link) {
> > > >  		ret = pci->ops->start_link(pci);
> > > >  		if (ret)
> > > > -			goto err_free_msi;
> > > > +			goto err_edma_remove;
> > > >  	}
> > > >  
> > > >  	/* Ignore errors, the link may come up later */
> > > > @@ -430,6 +434,9 @@ int dw_pcie_host_init(struct pcie_port *pp)
> > > >  	if (pci->ops && pci->ops->stop_link)
> > > >  		pci->ops->stop_link(pci);
> > > >  
> > > > +err_edma_remove:
> > > > +	dw_pcie_edma_remove(pci);
> > > > +
> > > >  err_free_msi:
> > > >  	if (pp->has_msi_ctrl)
> > > >  		dw_pcie_free_msi(pp);
> > > > @@ -452,6 +459,8 @@ void dw_pcie_host_deinit(struct pcie_port *pp)
> > > >  	if (pci->ops && pci->ops->stop_link)
> > > >  		pci->ops->stop_link(pci);
> > > >  
> > > > +	dw_pcie_edma_remove(pci);
> > > > +
> > > >  	if (pp->has_msi_ctrl)
> > > >  		dw_pcie_free_msi(pp);
> > > >  
> > > > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> > > > index 4a95a7b112e9..dbe39a7ecb71 100644
> > > > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > > > +++ b/drivers/pci/controller/dwc/pcie-designware.c
> > > 
> > > [...]
> > > 
> > > > +int dw_pcie_edma_detect(struct dw_pcie *pci)
> > > > +{
> > > > +	int ret;
> > > > +
> > > > +	pci->edma.dev = pci->dev;
> > > > +	if (!pci->edma.ops)
> > > > +		pci->edma.ops = &dw_pcie_edma_ops;
> > > > +	pci->edma.flags |= DW_EDMA_CHIP_LOCAL;
> > > > +
> > 
> > > > +	pci->edma_unroll_enabled = dw_pcie_edma_unroll_enabled(pci);
> > > 
> > > Is is possible to continue the unroll path for eDMA if iATU unroll is enabled?
> > 
> > Don't get it. Could you elaborate your question in more details?
> > Are you talking about using the same flag for both eDMA and iATU
> > unrolled space? If so then most likely yes. But in that case the
> > iatu_unroll_enabled flag name and semantics need to be changed.
> > 
> 

> If iATU has unroll enabled then I think we can assume that edma will also be
> the same. So I was wondering if we could just depend on iatu_unroll_enabled
> here.

I thought about that, but then I decided it was easier to just define
a new flag. Anyway according to the hw manuals indeed the unroll
mapping is enabled either for both iATU and eDMA modules or for none
of them just because they are mapped over a single space. It's
determined by the internal VHL parameter CC_UNROLL_ENABLE.
On the second thought I agree with you then. I'll convert the
iatu_unroll_enabled flag into a more generic 'reg_unroll' and make
sure it's used for both modules.

> 
> > > 
> > > > +	if (pci->edma_unroll_enabled && pci->iatu_unroll_enabled) {
> > > > +		pci->edma.mf = EDMA_MF_EDMA_UNROLL;
> > > > +		if (pci->atu_base != pci->dbi_base + DEFAULT_DBI_ATU_OFFSET)
> > > > +			pci->edma.reg_base = pci->atu_base + PCIE_DMA_UNROLL_BASE;
> > > > +		else
> > > > +			pci->edma.reg_base = pci->dbi_base + DEFAULT_DBI_DMA_OFFSET;
> > > 
> > 
> > > This assumption won't work on all platforms. Atleast on our platform, the
> > > offsets vary. So I'd suggest to try getting the reg_base from DT first and use
> > > these offsets as a fallback as we do for iATU.
> > 
> > I don't know how the eDMA offset can vary at least concerning the
> > normal DW PCIe setup. In any case the DW eDMA controller CSRs are
> > mapped in the same way as the iATU space: CS2=1 CDM=1. They are either
> > created as an unrolled region mapped into the particular MMIO space
> > (as a separate MMIO space or as a part of the DBI space), or
> > accessible over the PL viewports (as a part of the Port Logic CSRs).
> > Nothing else is described in the hardware manuals. Based on that I
> > don't see a reason to add one more reg space binding.
> > 
> 

> This is not true. Vendors can customize the iATU location inside DBI region
> for unroll too. That's one of the reason why dw_pcie_iatu_detect() works on
> qcom platforms as it tries to get iatu address from DT first and then falls
> back to the default offset if not found.
> 
> So please define an additional DT region for edma.

It's obvious that iATU location can vary. I never said it didn't. We
are talking about eDMA here. In accordance with what the DW PCIe hw
manuals say eDMA always resides the same space as the iATU. The space
is enabled by setting the CS2=1 and CDM=1 wires in case of the Native
Controller DBI access. In this case eDMA is defined with the 0x80000
offset over the iATU base address while the iATU base can be placed at
whatever region platform engineer needs.

Alternatively the AXI Bridge-based DBI access can be enabled thus
having the DBI+iATU+eDMA mapped over the same MMIO space with
respective offsets 0x0;0x300000;0x380000. This case is handled in the
branch of the conditional statement above if it's found that iATU base
is having the default offset with respect to the DBI base address
(pci->atu_base == pci->dbi_base + DEFAULT_DBI_ATU_OFFSET).

To sum up seeing I couldn't find the eDMA region defined in the qcom
bindings and judging by what you say doesn't really contradict to what
is done in my code, I guess there must be some misunderstanding either in
what you see in the code above or what I understand from what you say.
So please be more specific what offsets and whether they are really
different from what I use in the code above.

What I can suggest to modify in my solution is:
1) Make sure that the iATU/eDMA space fits the range
[atu_base; atu_base + atu_size]. If it doesn't just return an error.
2) Just realised that
DEFAULT_DBI_DMA_OFFSET = DEFAULT_DBI_ATU_OFFSET + PCIE_DMA_UNROLL_BASE,
so my conditional statement in the subject can be dropped thus
having the eDMA CSRs base address calculated as:
pci->edma.reg_base = pci->atu_base + PCIE_DMA_UNROLL_BASE;

-Sergey

> 
> > > 
> > > > +	} else {
> > > > +		pci->edma.mf = EDMA_MF_EDMA_LEGACY;
> > > > +		pci->edma.reg_base = pci->dbi_base + PCIE_DMA_VIEWPORT_BASE;
> > > > +	}
> > > > +
> > > > +	ret = dw_pcie_edma_detect_channels(pci);
> > > > +	if (ret) {
> > > > +		dev_err(pci->dev, "Unexpected NoF eDMA channels found\n");
> > > > +		return ret;
> > > > +	}
> > > > +
> > > > +	/* Skip any further initialization if no eDMA found */
> > > 
> > 
> > > Should we introduce a new Kconfig option for enabling eDMA? My concern here is,
> > > if eDMA is really needed for an usecase and if the platform support is broken
> > > somehow (DT issues?), then we'll just simply go ahead without probe failure and
> > > it may break somewhere else.
> > > 
> > > And we are returning errors if something wrong happens during eDMA probe. This
> > > might annoy the existing users who don't care about eDMA but turning those
> > > errors to debug will affect the real users of eDMA.
> > > 
> > > For these reasons, I think it'd be better to probe eDMA only if the Kconfig
> > > option is enabled (which would be disabled by default). And properly return the
> > > failure.
> > 
> > I don't see a need in introducing of a new parametrization. Neither
> > there is a point in dropping the eDMA support on all the platforms for
> > the sake of some hypothetically malfunction hardware.
> 
> I'm not talking about "hypothetically malfunction hardware" but real customized
> ones like all Qcom platforms supporting PCIe. As I said in my previous comment,
> the default eDMA offset won't work on Qcom platforms. So if this driver tries
> to access the registers based on the default offset, it may result in SMMU
> errors. The edma region needs to be defined in DT for probing edma correctly.
> 
> But even if we add dt support for edma and probe edma unconditionally, we'd be
> breaking the dts compatibility with older ones that don't define it.
> 
> > Regarding the
> > config, the DW eDMA driver already has one. It's CONFIG_DW_EDMA which
> > can be used for what you say. Though I need to fix this patch a bit so
> > the -ENODEV errno returned from the dw_edma_probe() method would be
> > ignored in the dw_pcie_edma_detect() procedure to support the case of
> > the disabled DW eDMA driver.
> > 
> 
> Please do so.
> 
> Thanks,
> Mani
> 
> > -Sergey
> > 
> > > 
> > > Thanks,
> > > Mani

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

* Re: [PATCH 25/25] PCI: dwc: Add DW eDMA engine support
  2022-04-28 14:05         ` Serge Semin
@ 2022-04-28 17:09           ` Manivannan Sadhasivam
  2022-04-29 16:13             ` Serge Semin
  0 siblings, 1 reply; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-04-28 17:09 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Lorenzo Pieralisi, Rob Herring,
	Krzysztof Wilczyński, Alexey Malahov, Pavel Parkhomenko,
	linux-pci, dmaengine, linux-kernel

On Thu, Apr 28, 2022 at 05:05:23PM +0300, Serge Semin wrote:

[...]

> > If iATU has unroll enabled then I think we can assume that edma will also be
> > the same. So I was wondering if we could just depend on iatu_unroll_enabled
> > here.
> 
> I thought about that, but then I decided it was easier to just define
> a new flag. Anyway according to the hw manuals indeed the unroll
> mapping is enabled either for both iATU and eDMA modules or for none
> of them just because they are mapped over a single space. It's
> determined by the internal VHL parameter CC_UNROLL_ENABLE.
> On the second thought I agree with you then. I'll convert the
> iatu_unroll_enabled flag into a more generic 'reg_unroll' and make
> sure it's used for both modules.
> 

Sounds good!

> > 
> > > > 
> > > > > +	if (pci->edma_unroll_enabled && pci->iatu_unroll_enabled) {
> > > > > +		pci->edma.mf = EDMA_MF_EDMA_UNROLL;
> > > > > +		if (pci->atu_base != pci->dbi_base + DEFAULT_DBI_ATU_OFFSET)
> > > > > +			pci->edma.reg_base = pci->atu_base + PCIE_DMA_UNROLL_BASE;
> > > > > +		else
> > > > > +			pci->edma.reg_base = pci->dbi_base + DEFAULT_DBI_DMA_OFFSET;
> > > > 
> > > 
> > > > This assumption won't work on all platforms. Atleast on our platform, the
> > > > offsets vary. So I'd suggest to try getting the reg_base from DT first and use
> > > > these offsets as a fallback as we do for iATU.
> > > 
> > > I don't know how the eDMA offset can vary at least concerning the
> > > normal DW PCIe setup. In any case the DW eDMA controller CSRs are
> > > mapped in the same way as the iATU space: CS2=1 CDM=1. They are either
> > > created as an unrolled region mapped into the particular MMIO space
> > > (as a separate MMIO space or as a part of the DBI space), or
> > > accessible over the PL viewports (as a part of the Port Logic CSRs).
> > > Nothing else is described in the hardware manuals. Based on that I
> > > don't see a reason to add one more reg space binding.
> > > 
> > 
> 
> > This is not true. Vendors can customize the iATU location inside DBI region
> > for unroll too. That's one of the reason why dw_pcie_iatu_detect() works on
> > qcom platforms as it tries to get iatu address from DT first and then falls
> > back to the default offset if not found.
> > 
> > So please define an additional DT region for edma.
> 
> It's obvious that iATU location can vary. I never said it didn't. We
> are talking about eDMA here. In accordance with what the DW PCIe hw
> manuals say eDMA always resides the same space as the iATU. The space
> is enabled by setting the CS2=1 and CDM=1 wires in case of the Native
> Controller DBI access. In this case eDMA is defined with the 0x80000
> offset over the iATU base address while the iATU base can be placed at
> whatever region platform engineer needs.
> 
> Alternatively the AXI Bridge-based DBI access can be enabled thus
> having the DBI+iATU+eDMA mapped over the same MMIO space with
> respective offsets 0x0;0x300000;0x380000. This case is handled in the
> branch of the conditional statement above if it's found that iATU base
> is having the default offset with respect to the DBI base address
> (pci->atu_base == pci->dbi_base + DEFAULT_DBI_ATU_OFFSET).
> 
> To sum up seeing I couldn't find the eDMA region defined in the qcom
> bindings and judging by what you say doesn't really contradict to what
> is done in my code, I guess there must be some misunderstanding either in
> what you see in the code above or what I understand from what you say.
> So please be more specific what offsets and whether they are really
> different from what I use in the code above.
> 

You won't see any edma register offset because no one bothered to define it
since it was not used until now. But the memory region should've been
documented...

Anyway, here is the offset for the Qcom SoC I'm currently working on:

DBI  - 0x0
iATU - 0x1000
eDMA - 0x2000

As you can see, these offsets doesn't really fit in both the cases you shared
above.

I don't have the knowledge about the internal representation of the IP or what
customization Qcom did apart from some high level information.

Hope this clarifies!

Thanks,
Mani

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

* Re: [PATCH 25/25] PCI: dwc: Add DW eDMA engine support
  2022-04-28 17:09           ` Manivannan Sadhasivam
@ 2022-04-29 16:13             ` Serge Semin
  2022-04-29 17:20               ` Manivannan Sadhasivam
  0 siblings, 1 reply; 79+ messages in thread
From: Serge Semin @ 2022-04-29 16:13 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Lorenzo Pieralisi, Rob Herring,
	Krzysztof Wilczyński, Alexey Malahov, Pavel Parkhomenko,
	linux-pci, dmaengine, linux-kernel

On Thu, Apr 28, 2022 at 10:39:29PM +0530, Manivannan Sadhasivam wrote:
> On Thu, Apr 28, 2022 at 05:05:23PM +0300, Serge Semin wrote:
> 
> [...]
> 
> > > If iATU has unroll enabled then I think we can assume that edma will also be
> > > the same. So I was wondering if we could just depend on iatu_unroll_enabled
> > > here.
> > 
> > I thought about that, but then I decided it was easier to just define
> > a new flag. Anyway according to the hw manuals indeed the unroll
> > mapping is enabled either for both iATU and eDMA modules or for none
> > of them just because they are mapped over a single space. It's
> > determined by the internal VHL parameter CC_UNROLL_ENABLE.
> > On the second thought I agree with you then. I'll convert the
> > iatu_unroll_enabled flag into a more generic 'reg_unroll' and make
> > sure it's used for both modules.
> > 
> 
> Sounds good!
> 
> > > 
> > > > > 
> > > > > > +	if (pci->edma_unroll_enabled && pci->iatu_unroll_enabled) {
> > > > > > +		pci->edma.mf = EDMA_MF_EDMA_UNROLL;
> > > > > > +		if (pci->atu_base != pci->dbi_base + DEFAULT_DBI_ATU_OFFSET)
> > > > > > +			pci->edma.reg_base = pci->atu_base + PCIE_DMA_UNROLL_BASE;
> > > > > > +		else
> > > > > > +			pci->edma.reg_base = pci->dbi_base + DEFAULT_DBI_DMA_OFFSET;
> > > > > 
> > > > 
> > > > > This assumption won't work on all platforms. Atleast on our platform, the
> > > > > offsets vary. So I'd suggest to try getting the reg_base from DT first and use
> > > > > these offsets as a fallback as we do for iATU.
> > > > 
> > > > I don't know how the eDMA offset can vary at least concerning the
> > > > normal DW PCIe setup. In any case the DW eDMA controller CSRs are
> > > > mapped in the same way as the iATU space: CS2=1 CDM=1. They are either
> > > > created as an unrolled region mapped into the particular MMIO space
> > > > (as a separate MMIO space or as a part of the DBI space), or
> > > > accessible over the PL viewports (as a part of the Port Logic CSRs).
> > > > Nothing else is described in the hardware manuals. Based on that I
> > > > don't see a reason to add one more reg space binding.
> > > > 
> > > 
> > 
> > > This is not true. Vendors can customize the iATU location inside DBI region
> > > for unroll too. That's one of the reason why dw_pcie_iatu_detect() works on
> > > qcom platforms as it tries to get iatu address from DT first and then falls
> > > back to the default offset if not found.
> > > 
> > > So please define an additional DT region for edma.
> > 
> > It's obvious that iATU location can vary. I never said it didn't. We
> > are talking about eDMA here. In accordance with what the DW PCIe hw
> > manuals say eDMA always resides the same space as the iATU. The space
> > is enabled by setting the CS2=1 and CDM=1 wires in case of the Native
> > Controller DBI access. In this case eDMA is defined with the 0x80000
> > offset over the iATU base address while the iATU base can be placed at
> > whatever region platform engineer needs.
> > 
> > Alternatively the AXI Bridge-based DBI access can be enabled thus
> > having the DBI+iATU+eDMA mapped over the same MMIO space with
> > respective offsets 0x0;0x300000;0x380000. This case is handled in the
> > branch of the conditional statement above if it's found that iATU base
> > is having the default offset with respect to the DBI base address
> > (pci->atu_base == pci->dbi_base + DEFAULT_DBI_ATU_OFFSET).
> > 
> > To sum up seeing I couldn't find the eDMA region defined in the qcom
> > bindings and judging by what you say doesn't really contradict to what
> > is done in my code, I guess there must be some misunderstanding either in
> > what you see in the code above or what I understand from what you say.
> > So please be more specific what offsets and whether they are really
> > different from what I use in the code above.
> > 
> 
> You won't see any edma register offset because no one bothered to define it
> since it was not used until now. But the memory region should've been
> documented...
> 

> Anyway, here is the offset for the Qcom SoC I'm currently working on:
> 
> DBI  - 0x0
> iATU - 0x1000
> eDMA - 0x2000

Finally we've got to something. Earlier you said:

> > > This is not true. Vendors can customize the iATU location inside DBI region
> > > for unroll too.

Actually it is if we are talking about the standard Syopsys DW PCIe
IP-CoreConsultant methods, which don't imply any eDMA base address
customization parameter. Thus there must be some address translation
performed at some layer before the address reaches the DW PCIe DBI
interface. So it's platform-specific. That happens in your case too.

> > > That's one of the reason why dw_pcie_iatu_detect() works on
> > > qcom platforms as it tries to get iatu address from DT first and then falls
> > > back to the default offset if not found.
> 
> As you can see, these offsets doesn't really fit in both the cases you shared
> above.

Seeing the iATU address bits layout can be changed the next
reg-space calculation code shall work for all the discussed cases:

if (!unroll) {
	pci->edma.reg_base = pci->dbi_base + PCIE_DMA_VIEWPORT_BASE;
} else if (!pci->edma.reg_base) {
	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
	if (res) {
		pci->edma.reg_base = devm_ioremap_resource(dev, res);
		if (IS_ERR(pci->edma.reg_base))
			return PTR_ERR(pci->edma.reg_base);
	} else (pci->atu_size >= 2 * 0x80000) {
		pci->edma.reg_base = pci->atu_base + 0x80000;
	} else {
		/* No standard eDMA CSRs mapping found. Just skip */
		return 0;
	}
} else {
	/* pci->edma.reg_base can be specified by the platform code. This shall
	 * be useful for the tegra194 or intel gw SoCs. The former
	 * platform has the "atu_dma" resource declared which implies
	 * having the joint iATU+eDMA CSR space, while the later has
	 * specific iATU offset with respect to the DBI base address
	 * (address is two bits shorter).
	 */
}

-Sergey

> 
> I don't have the knowledge about the internal representation of the IP or what
> customization Qcom did apart from some high level information.
> 
> Hope this clarifies!
> 
> Thanks,
> Mani

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

* Re: [PATCH 25/25] PCI: dwc: Add DW eDMA engine support
  2022-04-29 16:13             ` Serge Semin
@ 2022-04-29 17:20               ` Manivannan Sadhasivam
  0 siblings, 0 replies; 79+ messages in thread
From: Manivannan Sadhasivam @ 2022-04-29 17:20 UTC (permalink / raw)
  To: Serge Semin
  Cc: Serge Semin, Gustavo Pimentel, Vinod Koul, Jingoo Han,
	Bjorn Helgaas, Frank Li, Lorenzo Pieralisi, Rob Herring,
	Krzysztof Wilczyński, Alexey Malahov, Pavel Parkhomenko,
	linux-pci, dmaengine, linux-kernel

On Fri, Apr 29, 2022 at 07:13:48PM +0300, Serge Semin wrote:
> On Thu, Apr 28, 2022 at 10:39:29PM +0530, Manivannan Sadhasivam wrote:
> > On Thu, Apr 28, 2022 at 05:05:23PM +0300, Serge Semin wrote:
> > 
> > [...]
> > 
> > > > If iATU has unroll enabled then I think we can assume that edma will also be
> > > > the same. So I was wondering if we could just depend on iatu_unroll_enabled
> > > > here.
> > > 
> > > I thought about that, but then I decided it was easier to just define
> > > a new flag. Anyway according to the hw manuals indeed the unroll
> > > mapping is enabled either for both iATU and eDMA modules or for none
> > > of them just because they are mapped over a single space. It's
> > > determined by the internal VHL parameter CC_UNROLL_ENABLE.
> > > On the second thought I agree with you then. I'll convert the
> > > iatu_unroll_enabled flag into a more generic 'reg_unroll' and make
> > > sure it's used for both modules.
> > > 
> > 
> > Sounds good!
> > 
> > > > 
> > > > > > 
> > > > > > > +	if (pci->edma_unroll_enabled && pci->iatu_unroll_enabled) {
> > > > > > > +		pci->edma.mf = EDMA_MF_EDMA_UNROLL;
> > > > > > > +		if (pci->atu_base != pci->dbi_base + DEFAULT_DBI_ATU_OFFSET)
> > > > > > > +			pci->edma.reg_base = pci->atu_base + PCIE_DMA_UNROLL_BASE;
> > > > > > > +		else
> > > > > > > +			pci->edma.reg_base = pci->dbi_base + DEFAULT_DBI_DMA_OFFSET;
> > > > > > 
> > > > > 
> > > > > > This assumption won't work on all platforms. Atleast on our platform, the
> > > > > > offsets vary. So I'd suggest to try getting the reg_base from DT first and use
> > > > > > these offsets as a fallback as we do for iATU.
> > > > > 
> > > > > I don't know how the eDMA offset can vary at least concerning the
> > > > > normal DW PCIe setup. In any case the DW eDMA controller CSRs are
> > > > > mapped in the same way as the iATU space: CS2=1 CDM=1. They are either
> > > > > created as an unrolled region mapped into the particular MMIO space
> > > > > (as a separate MMIO space or as a part of the DBI space), or
> > > > > accessible over the PL viewports (as a part of the Port Logic CSRs).
> > > > > Nothing else is described in the hardware manuals. Based on that I
> > > > > don't see a reason to add one more reg space binding.
> > > > > 
> > > > 
> > > 
> > > > This is not true. Vendors can customize the iATU location inside DBI region
> > > > for unroll too. That's one of the reason why dw_pcie_iatu_detect() works on
> > > > qcom platforms as it tries to get iatu address from DT first and then falls
> > > > back to the default offset if not found.
> > > > 
> > > > So please define an additional DT region for edma.
> > > 
> > > It's obvious that iATU location can vary. I never said it didn't. We
> > > are talking about eDMA here. In accordance with what the DW PCIe hw
> > > manuals say eDMA always resides the same space as the iATU. The space
> > > is enabled by setting the CS2=1 and CDM=1 wires in case of the Native
> > > Controller DBI access. In this case eDMA is defined with the 0x80000
> > > offset over the iATU base address while the iATU base can be placed at
> > > whatever region platform engineer needs.
> > > 
> > > Alternatively the AXI Bridge-based DBI access can be enabled thus
> > > having the DBI+iATU+eDMA mapped over the same MMIO space with
> > > respective offsets 0x0;0x300000;0x380000. This case is handled in the
> > > branch of the conditional statement above if it's found that iATU base
> > > is having the default offset with respect to the DBI base address
> > > (pci->atu_base == pci->dbi_base + DEFAULT_DBI_ATU_OFFSET).
> > > 
> > > To sum up seeing I couldn't find the eDMA region defined in the qcom
> > > bindings and judging by what you say doesn't really contradict to what
> > > is done in my code, I guess there must be some misunderstanding either in
> > > what you see in the code above or what I understand from what you say.
> > > So please be more specific what offsets and whether they are really
> > > different from what I use in the code above.
> > > 
> > 
> > You won't see any edma register offset because no one bothered to define it
> > since it was not used until now. But the memory region should've been
> > documented...
> > 
> 
> > Anyway, here is the offset for the Qcom SoC I'm currently working on:
> > 
> > DBI  - 0x0
> > iATU - 0x1000
> > eDMA - 0x2000
> 
> Finally we've got to something. Earlier you said:
> 
> > > > This is not true. Vendors can customize the iATU location inside DBI region
> > > > for unroll too.
> 
> Actually it is if we are talking about the standard Syopsys DW PCIe
> IP-CoreConsultant methods, which don't imply any eDMA base address
> customization parameter. Thus there must be some address translation
> performed at some layer before the address reaches the DW PCIe DBI
> interface. So it's platform-specific. That happens in your case too.
> 

Seems like it.

> > > > That's one of the reason why dw_pcie_iatu_detect() works on
> > > > qcom platforms as it tries to get iatu address from DT first and then falls
> > > > back to the default offset if not found.
> > 
> > As you can see, these offsets doesn't really fit in both the cases you shared
> > above.
> 
> Seeing the iATU address bits layout can be changed the next
> reg-space calculation code shall work for all the discussed cases:
> 
> if (!unroll) {
> 	pci->edma.reg_base = pci->dbi_base + PCIE_DMA_VIEWPORT_BASE;
> } else if (!pci->edma.reg_base) {
> 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma");
> 	if (res) {
> 		pci->edma.reg_base = devm_ioremap_resource(dev, res);
> 		if (IS_ERR(pci->edma.reg_base))
> 			return PTR_ERR(pci->edma.reg_base);

This should work for me. Thanks for the work!

Regards,
Mani

> 	} else (pci->atu_size >= 2 * 0x80000) {
> 		pci->edma.reg_base = pci->atu_base + 0x80000;
> 	} else {
> 		/* No standard eDMA CSRs mapping found. Just skip */
> 		return 0;
> 	}
> } else {
> 	/* pci->edma.reg_base can be specified by the platform code. This shall
> 	 * be useful for the tegra194 or intel gw SoCs. The former
> 	 * platform has the "atu_dma" resource declared which implies
> 	 * having the joint iATU+eDMA CSR space, while the later has
> 	 * specific iATU offset with respect to the DBI base address
> 	 * (address is two bits shorter).
> 	 */
> }
> 
> -Sergey
> 
> > 
> > I don't have the knowledge about the internal representation of the IP or what
> > customization Qcom did apart from some high level information.
> > 
> > Hope this clarifies!
> > 
> > Thanks,
> > Mani

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

end of thread, other threads:[~2022-04-29 17:20 UTC | newest]

Thread overview: 79+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-24  1:48 [PATCH 00/25] dmaengine: dw-edma: Add RP/EP local DMA controllers support Serge Semin
2022-03-24  1:48 ` [PATCH 01/25] dmaengine: dw-edma: Drop dma_slave_config.direction field usage Serge Semin
2022-03-24 13:30   ` Manivannan Sadhasivam
2022-04-05 11:15     ` Serge Semin
2022-03-24  1:48 ` [PATCH 02/25] dmaengine: dw-edma: Fix eDMA Rd/Wr-channels and DMA-direction semantics Serge Semin
2022-03-24  1:48 ` [PATCH 03/25] dma-direct: take dma-ranges/offsets into account in resource mapping Serge Semin
2022-03-24 11:30   ` Robin Murphy
2022-04-17 22:44     ` Serge Semin
2022-04-20  7:12       ` Christoph Hellwig
2022-04-20  8:32         ` Serge Semin
2022-04-20  8:47           ` Christoph Hellwig
2022-04-20  8:55             ` Serge Semin
2022-04-21 14:45               ` Christoph Hellwig
2022-04-21 17:35                 ` Serge Semin
2022-04-21 20:51                   ` Robin Murphy
2022-04-24 21:46                     ` Serge Semin
2022-03-24  1:48 ` [PATCH 04/25] dmaengine: Fix dma_slave_config.dst_addr description Serge Semin
2022-03-24 14:08   ` Manivannan Sadhasivam
2022-03-31  5:38     ` Vinod Koul
2022-03-31  7:13       ` Serge Semin
2022-03-31 10:50         ` Manivannan Sadhasivam
2022-03-24  1:48 ` [PATCH 05/25] dmaengine: dw-edma: Convert ll/dt phys-address to PCIe bus/DMA address Serge Semin
2022-03-24 16:23   ` Manivannan Sadhasivam
2022-03-24  1:48 ` [PATCH 06/25] dmaengine: dw-edma: Fix missing src/dst address of the interleaved xfers Serge Semin
2022-03-24 16:26   ` Manivannan Sadhasivam
2022-03-24  1:48 ` [PATCH 07/25] dmaengine: dw-edma: Don't permit non-inc " Serge Semin
2022-03-24 17:15   ` Manivannan Sadhasivam
2022-04-17 22:59     ` Serge Semin
2022-03-24  1:48 ` [PATCH 08/25] dmaengine: dw-edma: Fix invalid interleaved xfers semantics Serge Semin
2022-03-24  1:48 ` [PATCH 09/25] dmaengine: dw-edma: Add CPU to PCIe bus address translation Serge Semin
2022-03-24 17:25   ` Manivannan Sadhasivam
2022-03-24  1:48 ` [PATCH 10/25] dmaengine: dw-edma: Add PCIe bus address getter to the remote EP glue-driver Serge Semin
2022-03-24 17:41   ` Manivannan Sadhasivam
2022-03-24  1:48 ` [PATCH 11/25] dmaengine: dw-edma: Drop chancnt initialization Serge Semin
2022-03-24 17:42   ` Manivannan Sadhasivam
2022-03-24  1:48 ` [PATCH 12/25] dmaengine: dw-edma: Fix DebugFS reg entry type Serge Semin
2022-03-24 17:48   ` Manivannan Sadhasivam
2022-03-24  1:48 ` [PATCH 13/25] dmaengine: dw-edma: Stop checking debugfs_create_*() return value Serge Semin
2022-03-24 18:12   ` Manivannan Sadhasivam
2022-03-24  1:48 ` [PATCH 14/25] dmaengine: dw-edma: Add dw_edma prefix to the DebugFS nodes descriptor Serge Semin
2022-03-24 18:14   ` Manivannan Sadhasivam
2022-03-24  1:48 ` [PATCH 15/25] dmaengine: dw-edma: Convert DebugFS descs to being kz-allocated Serge Semin
2022-03-25  6:03   ` Manivannan Sadhasivam
2022-03-25  6:42     ` Manivannan Sadhasivam
2022-04-18  7:17     ` Serge Semin
2022-03-24  1:48 ` [PATCH 16/25] dmaengine: dw-edma: Simplify the DebugFS context CSRs init procedure Serge Semin
2022-03-25  6:27   ` Manivannan Sadhasivam
2022-03-25  6:31     ` Manivannan Sadhasivam
2022-04-18  8:23     ` Serge Semin
2022-03-24  1:48 ` [PATCH 17/25] dmaengine: dw-edma: Move eDMA data pointer to DebugFS node descriptor Serge Semin
2022-03-25  6:35   ` Manivannan Sadhasivam
2022-03-24  1:48 ` [PATCH 18/25] dmaengine: dw-edma: Join Write/Read channels into a single device Serge Semin
2022-03-25  7:34   ` Manivannan Sadhasivam
2022-03-24  1:48 ` [PATCH 19/25] dmaengine: dw-edma: Use DMA-engine device DebugFS subdirectory Serge Semin
2022-03-25  7:41   ` Manivannan Sadhasivam
2022-03-24  1:48 ` [PATCH 20/25] dmaengine: dw-edma: Use non-atomic io-64 methods Serge Semin
2022-03-25  8:28   ` Manivannan Sadhasivam
2022-04-18 11:37     ` Serge Semin
2022-03-24  1:48 ` [PATCH 21/25] dmaengine: dw-edma: Drop DT-region allocation Serge Semin
2022-03-25  8:33   ` Manivannan Sadhasivam
2022-03-24  1:48 ` [PATCH 22/25] dmaengine: dw-edma: Replace chip ID number with device name Serge Semin
2022-03-25 10:02   ` Manivannan Sadhasivam
2022-04-18 12:17     ` Serge Semin
2022-03-24  1:48 ` [PATCH 23/25] dmaengine: dw-edma: Bypass dma-ranges mapping for the local setup Serge Semin
2022-03-25 18:10   ` Manivannan Sadhasivam
2022-04-18 13:36     ` Serge Semin
2022-03-24  1:48 ` [PATCH 24/25] dmaengine: dw-edma: Skip cleanup procedure if no private data found Serge Semin
2022-03-25 18:15   ` Manivannan Sadhasivam
2022-04-18 13:48     ` Serge Semin
2022-04-23 14:45       ` Manivannan Sadhasivam
2022-03-24  1:48 ` [PATCH 25/25] PCI: dwc: Add DW eDMA engine support Serge Semin
2022-03-28 14:15   ` Manivannan Sadhasivam
2022-04-19 20:54     ` Serge Semin
2022-04-23 14:40       ` Manivannan Sadhasivam
2022-04-25  5:22         ` Manivannan Sadhasivam
2022-04-28 14:05         ` Serge Semin
2022-04-28 17:09           ` Manivannan Sadhasivam
2022-04-29 16:13             ` Serge Semin
2022-04-29 17:20               ` Manivannan Sadhasivam

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).