Re: [PATCH v1 3/6] PCI: dwc: Add HDMA support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Jan 19, 2024 at 06:30:19PM +0530, Mrinmay Sarkar wrote:
> From: Manivannan Sadhasivam <manivannan.sadhasivam@xxxxxxxxxx>
> 
> Hyper DMA (HDMA) is already supported by the dw-edma dmaengine driver.
> Unlike it's predecessor Embedded DMA (eDMA), HDMA supports only the
> unrolled mapping format. So the platform drivers need to provide a valid
> base address of the CSRs. Also, there is no standard way to auto detect
> the number of available read/write channels in a platform. So the platform
> drivers has to provide that information as well.
> 
> For adding HDMA support, the mapping format set by the platform drivers is
> used to detect whether eDMA or HDMA is being used, since we cannot auto
> detect it in a sane way.
> 
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@xxxxxxxxxx>
> Signed-off-by: Mrinmay Sarkar <quic_msarkar@xxxxxxxxxxx>
> ---
>  drivers/pci/controller/dwc/pcie-designware.c | 55 ++++++++++++++++++++++++----
>  1 file changed, 47 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> index 96575b8..07a1f2d 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.c
> +++ b/drivers/pci/controller/dwc/pcie-designware.c
> @@ -880,7 +880,29 @@ static struct dw_edma_plat_ops dw_pcie_edma_ops = {
>  	.irq_vector = dw_pcie_edma_irq_vector,
>  };
>  
> -static int dw_pcie_edma_find_chip(struct dw_pcie *pci)
> +static int dw_pcie_find_hdma(struct dw_pcie *pci)
> +{
> +	/*
> +	 * Since HDMA supports only unrolled mapping, platform drivers need to
> +	 * provide a valid base address.
> +	 */
> +	if (!pci->edma.reg_base)
> +		return -ENODEV;
> +
> +	/*
> +	 * Since there is no standard way to detect the number of read/write
> +	 * HDMA channels, platform drivers are expected to provide the channel
> +	 * count. Let's also do a sanity check of them to make sure that the
> +	 * counts are within the limit specified by the spec.
> +	 */
> +	if (!pci->edma.ll_wr_cnt || pci->edma.ll_wr_cnt > dw_edma_get_max_wr_ch(pci->edma.mf) ||
> +	    !pci->edma.ll_rd_cnt || pci->edma.ll_rd_cnt > dw_edma_get_max_rd_ch(pci->edma.mf))
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static int dw_pcie_find_edma(struct dw_pcie *pci)
>  {
>  	u32 val;
>  
> @@ -912,13 +934,6 @@ static int dw_pcie_edma_find_chip(struct dw_pcie *pci)
>  		return -ENODEV;
>  	}
>  
> -	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.ll_wr_cnt = FIELD_GET(PCIE_DMA_NUM_WR_CHAN, val);
>  	pci->edma.ll_rd_cnt = FIELD_GET(PCIE_DMA_NUM_RD_CHAN, val);
>  
> @@ -930,6 +945,30 @@ static int dw_pcie_edma_find_chip(struct dw_pcie *pci)
>  	return 0;
>  }
>  
> +static int dw_pcie_edma_find_chip(struct dw_pcie *pci)
> +{
> +	int ret;
> +

> +	if (pci->edma.mf == EDMA_MF_HDMA_NATIVE) {
> +		ret = dw_pcie_find_hdma(pci);
> +		if (ret)
> +			return ret;
> +	} else {
> +		ret = dw_pcie_find_edma(pci);
> +		if (ret)
> +			return ret;
> +	}

Basically this change defines two versions of the eDMA info
initialization procedure:
1. use pre-defined CSRs mapping format and amount of channels,
2. auto-detect CSRs mapping and the amount of channels.
The second version also supports the optional CSRs mapping format
detection procedure by means of the DW_PCIE_CAP_EDMA_UNROLL flag
semantics. Thus should this patch is accepted there will be the
functionality duplication. I suggest to make things a bit more
flexible than that. Instead of creating the two types of the
init-methods selectable based on the mapping format, let's split up
the already available DW eDMA engine detection procedure into the next
three stages:
1. initialize DW eDMA data,
2. auto-detect the CSRs mapping format,
3. auto-detect the amount of channels.
and convert the later two to being optional. They will be skipped in case
if the mapping format or the amount of channels have been pre-defined
by the platform drivers. Thus we can keep the eDMA data init procedure
more linear thus easier to read, drop redundant DW_PCIE_CAP_EDMA_UNROLL flag
and use the new functionality for the Renesas R-Car S4-8's PCIe
controller (for which the auto-detection didn't work), for HDMA with compat
and _native_ CSRs mapping. See the attached patches for details:

0001-PCI-dwc-Fix-eDMA-mapping-info-string.patch
+- Just the eDMA log-message fix which will be useful in any case.

0002-PCI-dwc-Split-up-eDMA-parameters-auto-detection-proc.patch
+-> Split up the dw_pcie_edma_find_chip() method into three ones
described above.

0003-PCI-dwc-Convert-eDMA-mapping-detection-to-being-full.patch
+-> Skip the second stage the mapping format has been specified.

0004-PCI-dwc-Convert-eDMA-channels-detection-to-being-opt.patch
+-> Skip the amount of channels auto-detection if the amount has
already been specified.

0005-PCI-dwc-Drop-DW_PCIE_CAP_EDMA_UNROLL-flag.patch
+-> Drop the no longer needed DW_PCIE_CAP_EDMA_UNROLL flag.

After these patches are applied AFAICS the patches 5/6 and 6/6 of this
series shall work with no additional modification.

* Note I only build-tested the attached patches. So even though they
* aren't that much invasive please be read for a bit debugging.

-Serge(y)

> +
> +	pci->edma.dev = pci->dev;
> +
> +	if (!pci->edma.ops)
> +		pci->edma.ops = &dw_pcie_edma_ops;
> +
> +	pci->edma.flags |= DW_EDMA_CHIP_LOCAL;
> +
> +	return 0;
> +}
> +
>  static int dw_pcie_edma_irq_verify(struct dw_pcie *pci)
>  {
>  	struct platform_device *pdev = to_platform_device(pci->dev);
> -- 
> 2.7.4
> 
>From 9b600c17aa56b3949a040055cf82222c48b60bf3 Mon Sep 17 00:00:00 2001
From: Serge Semin <fancer.lancer@xxxxxxxxx>
Date: Fri, 2 Feb 2024 18:01:31 +0300
Subject: [PATCH 1/5] PCI: dwc: Fix eDMA mapping info string

DW PCIe controller can be equipped with the next types of DMA controllers:
1. eDMA controller with viewport-based CSRs access (so called legacy),
2. eDMA controller with unrolled CSRs mapping,
3. HDMA controller compatible with the eDMA unrolled CSRs mapping,
4. HDMA controller with native CSRs mapping.
The later three types imply having the DMA-engine CSRs _unrolled_ mapping.
Let's fix the info-message printed in the DW PCIe eDMA controller
detection procedure to comply with that.

Signed-off-by: Serge Semin <fancer.lancer@xxxxxxxxx>
---
 drivers/pci/controller/dwc/pcie-designware.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 7551e0fea5e9..454ea32ee70b 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -1018,7 +1018,7 @@ int dw_pcie_edma_detect(struct dw_pcie *pci)
 	}
 
 	dev_info(pci->dev, "eDMA: unroll %s, %hu wr, %hu rd\n",
-		 pci->edma.mf == EDMA_MF_EDMA_UNROLL ? "T" : "F",
+		 pci->edma.mf != EDMA_MF_EDMA_LEGACY ? "T" : "F",
 		 pci->edma.ll_wr_cnt, pci->edma.ll_rd_cnt);
 
 	return 0;
-- 
2.43.0

>From ca70e7dd9b84c9dd01124a13f624441c01f7c09d Mon Sep 17 00:00:00 2001
From: Serge Semin <fancer.lancer@xxxxxxxxx>
Date: Fri, 2 Feb 2024 18:18:39 +0300
Subject: [PATCH 2/5] PCI: dwc: Split up eDMA parameters auto-detection
 procedure

It turns out the DW HDMA controller parameters can't be auto-detected in
the same way as it's done for DW eDMA: HDMA has only the unrolled CSRs
mapping and has no way to find out the amount of the channels. For that
case the best choice would be to have the HDMA controller parameters
pre-defined by the platform drivers and to convert the implemented
auto-detection procedure to being optionally executed if no DMA-controller
parameters specified. As a preparation step before that let's split the
eDMA auto-detection into three stages:
1. initialize DW eDMA data,
2. auto-detect the CSRs mapping format,
3. auto-detect the amount of channels.

Note this commit doesn't imply the eDMA detection procedure semantics
change.

Signed-off-by: Serge Semin <fancer.lancer@xxxxxxxxx>
---
 drivers/pci/controller/dwc/pcie-designware.c | 33 +++++++++++++++-----
 1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 454ea32ee70b..149c7a2a12f2 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -878,7 +878,17 @@ static struct dw_edma_plat_ops dw_pcie_edma_ops = {
 	.irq_vector = dw_pcie_edma_irq_vector,
 };
 
-static int dw_pcie_edma_find_chip(struct dw_pcie *pci)
+static void dw_pcie_edma_init_data(struct dw_pcie *pci)
+{
+	pci->edma.dev = pci->dev;
+
+	if (!pci->edma.ops)
+		pci->edma.ops = &dw_pcie_edma_ops;
+
+	pci->edma.flags |= DW_EDMA_CHIP_LOCAL;
+}
+
+static int dw_pcie_edma_find_mf(struct dw_pcie *pci)
 {
 	u32 val;
 
@@ -900,8 +910,6 @@ static int dw_pcie_edma_find_chip(struct dw_pcie *pci)
 
 	if (val == 0xFFFFFFFF && pci->edma.reg_base) {
 		pci->edma.mf = EDMA_MF_EDMA_UNROLL;
-
-		val = dw_pcie_readl_dma(pci, PCIE_DMA_CTRL);
 	} else if (val != 0xFFFFFFFF) {
 		pci->edma.mf = EDMA_MF_EDMA_LEGACY;
 
@@ -910,12 +918,14 @@ static int dw_pcie_edma_find_chip(struct dw_pcie *pci)
 		return -ENODEV;
 	}
 
-	pci->edma.dev = pci->dev;
+	return 0;
+}
 
-	if (!pci->edma.ops)
-		pci->edma.ops = &dw_pcie_edma_ops;
+static int dw_pcie_edma_find_chan(struct dw_pcie *pci)
+{
+	u32 val;
 
-	pci->edma.flags |= DW_EDMA_CHIP_LOCAL;
+	val = dw_pcie_readl_dma(pci, PCIE_DMA_CTRL);
 
 	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);
@@ -992,8 +1002,15 @@ int dw_pcie_edma_detect(struct dw_pcie *pci)
 {
 	int ret;
 
+	dw_pcie_edma_init_data(pci);
+
 	/* Don't fail if no eDMA was found (for the backward compatibility) */
-	ret = dw_pcie_edma_find_chip(pci);
+	ret = dw_pcie_edma_find_mf(pci);
+	if (ret)
+		return 0;
+
+	/* Don't fail if no valid channels detected (for the backward compatibility) */
+	ret = dw_pcie_edma_find_chan(pci);
 	if (ret)
 		return 0;
 
-- 
2.43.0

>From f5149d0827d9d8b0ccaaaeb6309b1a86832cdddc Mon Sep 17 00:00:00 2001
From: Serge Semin <fancer.lancer@xxxxxxxxx>
Date: Fri, 2 Feb 2024 19:02:35 +0300
Subject: [PATCH 3/5] PCI: dwc: Convert eDMA mapping detection to being fully
 optional

The DW eDMA CSRs mapping detection procedure doesn't work for the DW HDMA
controller. Moreover it isn't that easy to distinguish HDMA from eDMA if
the former controller available in place of the later one. Thus seeing DW
HDMA controller has the unrolled CSRs mapping only there is no better
choice but to rely on the HDMA-capable platform drivers having the
DMA-engine mapping format specified. In order to permit that let's convert
the eDMA mapping format auto-detection to being fully optional: execute
the DMA Ctrl-based CSRs mapping auto-detection only if no mapping format
was specific.

Note the DW_PCIE_CAP_EDMA_UNROLL flag semantics also imply the mapping
auto-detection optionality. But it doesn't indicate the type of the
controller. It's merely a fixup for the DW PCIe eDMA controllers which for
some reason don't support the DMA Ctrl-based CSRs mapping auto-detection
procedure (see note regarding the Renesas R-Car S4-8's PCIe). So it can't
be utilized for DW HDMA auto-detection. But after this change is applied
the flag will get to be redundant and will be subject for removal in one
of the subsequent commit.

Signed-off-by: Serge Semin <fancer.lancer@xxxxxxxxx>
---
 drivers/pci/controller/dwc/pcie-designware.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 149c7a2a12f2..2243ffeb95b5 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -892,6 +892,14 @@ static int dw_pcie_edma_find_mf(struct dw_pcie *pci)
 {
 	u32 val;
 
+	/*
+	 * The platform drivers can pre-define the DMA controller mapping
+	 * format especially if the auto-detection procedure doesn't work for
+	 * them. In that case the CSRs base must be specified too.
+	 */
+	if (pci->edma.mf != EDMA_MF_EDMA_LEGACY)
+		return pci->edma.reg_base ? 0 : -EINVAL;
+
 	/*
 	 * Indirect eDMA CSRs access has been completely removed since v5.40a
 	 * thus no space is now reserved for the eDMA channels viewport and
-- 
2.43.0

>From 4f9668ad9e741b501476cd4457cf9ca9013ee6e3 Mon Sep 17 00:00:00 2001
From: Serge Semin <fancer.lancer@xxxxxxxxx>
Date: Fri, 2 Feb 2024 20:12:46 +0300
Subject: [PATCH 4/5] PCI: dwc: Convert eDMA channels detection to being
 optional

DW HDMA controller channels can't be auto-detected. Thus there is no way
but to rely on the HDMA-capable platform drivers having the number of
channels specified. In order to permit that convert the
dw_pcie_edma_find_chan() method to executing the DMA Ctrl CSR-based number
of channels detection procedure only if no channels amount was specified,
otherwise just sanity check the specified values.

Signed-off-by: Serge Semin <fancer.lancer@xxxxxxxxx>
---
 drivers/pci/controller/dwc/pcie-designware.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 2243ffeb95b5..4d53a71ab1b4 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -933,12 +933,20 @@ static int dw_pcie_edma_find_chan(struct dw_pcie *pci)
 {
 	u32 val;
 
-	val = dw_pcie_readl_dma(pci, PCIE_DMA_CTRL);
+	if (!pci->edma.ll_wr_cnt && !pci->edma.ll_rd_cnt) {
+		if (pci->edma.mf == EDMA_MF_HDMA_NATIVE)
+			return -EINVAL;
+
+		val = dw_pcie_readl_dma(pci, PCIE_DMA_CTRL);
 
-	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);
+		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);
+	}
 
-	/* Sanity check the channels count if the mapping was incorrect */
+	/*
+	 * Sanity check the channels count in case if the mapping was
+	 * incorrectly detected/specified by the glue-driver.
+	 */
 	if (!pci->edma.ll_wr_cnt || pci->edma.ll_wr_cnt > EDMA_MAX_WR_CH ||
 	    !pci->edma.ll_rd_cnt || pci->edma.ll_rd_cnt > EDMA_MAX_RD_CH)
 		return -EINVAL;
-- 
2.43.0

>From 9590af6f5114b07e4073083ecde9e563cc920410 Mon Sep 17 00:00:00 2001
From: Serge Semin <fancer.lancer@xxxxxxxxx>
Date: Fri, 2 Feb 2024 23:45:00 +0300
Subject: [PATCH 5/5] PCI: dwc: Drop DW_PCIE_CAP_EDMA_UNROLL flag

That flag was introduced in order to bypass the DW eDMA mapping format
auto-detection procedure and force the unrolled eDMA CSRs mapping
procedure. Since the same can be now reached just by pre-defining the
required mapping format, drop the flag and convert the Renesas R-Car S4-8
glue-driver to using the new approach.

Signed-off-by: Serge Semin <fancer.lancer@xxxxxxxxx>
---
 drivers/pci/controller/dwc/pcie-designware.c | 13 +++++--------
 drivers/pci/controller/dwc/pcie-designware.h |  5 ++---
 drivers/pci/controller/dwc/pcie-rcar-gen4.c  |  2 +-
 3 files changed, 8 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 4d53a71ab1b4..a49de18c9836 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -895,7 +895,10 @@ static int dw_pcie_edma_find_mf(struct dw_pcie *pci)
 	/*
 	 * The platform drivers can pre-define the DMA controller mapping
 	 * format especially if the auto-detection procedure doesn't work for
-	 * them. In that case the CSRs base must be specified too.
+	 * them (e.g. Renesas R-Car S4-8's PCIe controllers for unknown reason
+	 * have zeros in the eDMA CTRL register even though the HW-manual
+	 * explicitly states there must be FFs if the unrolled mapping is
+	 * enabled). In that case the CSRs base must be specified too.
 	 */
 	if (pci->edma.mf != EDMA_MF_EDMA_LEGACY)
 		return pci->edma.reg_base ? 0 : -EINVAL;
@@ -904,14 +907,8 @@ static int dw_pcie_edma_find_mf(struct dw_pcie *pci)
 	 * Indirect eDMA CSRs access has been completely removed since v5.40a
 	 * thus no space is now reserved for the eDMA channels viewport and
 	 * former DMA CTRL register is no longer fixed to FFs.
-	 *
-	 * Note that Renesas R-Car S4-8's PCIe controllers for unknown reason
-	 * have zeros in the eDMA CTRL register even though the HW-manual
-	 * explicitly states there must FFs if the unrolled mapping is enabled.
-	 * For such cases the low-level drivers are supposed to manually
-	 * activate the unrolled mapping to bypass the auto-detection procedure.
 	 */
-	if (dw_pcie_ver_is_ge(pci, 540A) || dw_pcie_cap_is(pci, EDMA_UNROLL))
+	if (dw_pcie_ver_is_ge(pci, 540A))
 		val = 0xFFFFFFFF;
 	else
 		val = dw_pcie_readl_dbi(pci, PCIE_DMA_VIEWPORT_BASE + PCIE_DMA_CTRL);
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 035df6bc7606..a666190e8b1b 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -54,9 +54,8 @@
 
 /* DWC PCIe controller capabilities */
 #define DW_PCIE_CAP_REQ_RES		0
-#define DW_PCIE_CAP_EDMA_UNROLL		1
-#define DW_PCIE_CAP_IATU_UNROLL		2
-#define DW_PCIE_CAP_CDM_CHECK		3
+#define DW_PCIE_CAP_IATU_UNROLL		1
+#define DW_PCIE_CAP_CDM_CHECK		2
 
 #define dw_pcie_cap_is(_pci, _cap) \
 	test_bit(DW_PCIE_CAP_ ## _cap, &(_pci)->caps)
diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index 3bc45e513b3d..5678d69c413a 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -255,7 +255,7 @@ static struct rcar_gen4_pcie *rcar_gen4_pcie_alloc(struct platform_device *pdev)
 	rcar->dw.ops = &dw_pcie_ops;
 	rcar->dw.dev = dev;
 	rcar->pdev = pdev;
-	dw_pcie_cap_set(&rcar->dw, EDMA_UNROLL);
+	rcar->dw.edma.mf = EDMA_MF_EDMA_UNROLL;
 	dw_pcie_cap_set(&rcar->dw, REQ_RES);
 	platform_set_drvdata(pdev, rcar);
 
-- 
2.43.0


[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux