linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC
@ 2022-01-26 19:50 Lad Prabhakar
  2022-01-26 19:50 ` [RFC PATCH 1/5] PCI: endpoint: Add ops and flag to support internal DMAC Lad Prabhakar
                   ` (6 more replies)
  0 siblings, 7 replies; 21+ messages in thread
From: Lad Prabhakar @ 2022-01-26 19:50 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Arnd Bergmann, Greg Kroah-Hartman,
	Marek Vasut, Yoshihiro Shimoda, Rob Herring, linux-pci,
	linux-renesas-soc
  Cc: linux-kernel, Prabhakar, Biju Das, Lad Prabhakar

Hi All,

The current PCIe EPF framework supports DMA data transfers using external
DMA only, this patch series aims to add support for platforms supporting
internal DMAC on PCIe for data transfers.

R-Car PCIe supports internal DMAC to transfer data between Internal Bus to
PCI Express and vice versa. Last patch fills up the required flags and ops
to support internal DMAC.

Patches 1-3 are for PCIe EPF core to support internal DMAC handling, patch
4/5 is to fix test cases based on the conversation [1].

Patches are based on top of [1] next branch.

[0] https://www.spinics.net/lists/linux-pci/msg92385.html
[1] https://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git

Cheers,
Prabhakar

Lad Prabhakar (5):
  PCI: endpoint: Add ops and flag to support internal DMAC
  PCI: endpoint: Add support to data transfer using internal dmac
  misc: pci_endpoint_test: Add driver data for Renesas RZ/G2{EHMN}
  misc: pci_endpoint_test: Add support to pass flags for buffer
    allocation
  PCI: rcar-ep: Add support for DMAC

 drivers/misc/pci_endpoint_test.c              |  56 ++++-
 drivers/pci/controller/pcie-rcar-ep.c         | 227 ++++++++++++++++++
 drivers/pci/controller/pcie-rcar.h            |  23 ++
 drivers/pci/endpoint/functions/pci-epf-test.c | 184 ++++++++++----
 drivers/pci/endpoint/pci-epf-core.c           |  32 +++
 include/linux/pci-epc.h                       |   8 +
 include/linux/pci-epf.h                       |   7 +
 7 files changed, 483 insertions(+), 54 deletions(-)

-- 
2.25.1


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

* [RFC PATCH 1/5] PCI: endpoint: Add ops and flag to support internal DMAC
  2022-01-26 19:50 [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC Lad Prabhakar
@ 2022-01-26 19:50 ` Lad Prabhakar
  2022-02-14  9:30   ` Manivannan Sadhasivam
  2022-01-26 19:50 ` [RFC PATCH 2/5] PCI: endpoint: Add support to data transfer using internal dmac Lad Prabhakar
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 21+ messages in thread
From: Lad Prabhakar @ 2022-01-26 19:50 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Arnd Bergmann, Greg Kroah-Hartman,
	Marek Vasut, Yoshihiro Shimoda, Rob Herring, linux-pci,
	linux-renesas-soc
  Cc: linux-kernel, Prabhakar, Biju Das, Lad Prabhakar

Add flag to indicate if PCIe EP supports internal DMAC and also add a
wrapper function which invokes dmac_transfer() callback which lands
in the PCIe EP driver.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
 drivers/pci/endpoint/pci-epf-core.c | 32 +++++++++++++++++++++++++++++
 include/linux/pci-epc.h             |  8 ++++++++
 include/linux/pci-epf.h             |  7 +++++++
 3 files changed, 47 insertions(+)

diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
index 9ed556936f48..f70576d0d4b2 100644
--- a/drivers/pci/endpoint/pci-epf-core.c
+++ b/drivers/pci/endpoint/pci-epf-core.c
@@ -239,6 +239,38 @@ void pci_epf_remove_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf)
 }
 EXPORT_SYMBOL_GPL(pci_epf_remove_vepf);
 
+/**
+ * pci_epf_internal_dmac_xfr() - transfer data between EPC and remote PCIe RC
+ * @epf: the EPF device that performs the data transfer operation
+ * @dma_dst: The destination address of the data transfer. It can be a physical
+ *	     address given by pci_epc_mem_alloc_addr or DMA mapping APIs.
+ * @dma_src: The source address of the data transfer. It can be a physical
+ *	     address given by pci_epc_mem_alloc_addr or DMA mapping APIs.
+ * @len: The size of the data transfer
+ *
+ * Invoke to transfer data between EPC and remote PCIe RC using internal dmac.
+ */
+int pci_epf_internal_dmac_xfr(struct pci_epf *epf, dma_addr_t dma_dst,
+			      dma_addr_t dma_src, size_t len,
+			      enum pci_epf_xfr_direction dir)
+{
+	struct pci_epc *epc = epf->epc;
+	int ret;
+
+	if (IS_ERR_OR_NULL(epc) || IS_ERR_OR_NULL(epf))
+		return -EINVAL;
+
+	if (!epc->ops->dmac_transfer)
+		return -EINVAL;
+
+	mutex_lock(&epf->lock);
+	ret = epc->ops->dmac_transfer(epc, epf, dma_dst, dma_src, len, dir);
+	mutex_unlock(&epf->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pci_epf_internal_dmac_xfr);
+
 /**
  * pci_epf_free_space() - free the allocated PCI EPF register space
  * @epf: the EPF device from whom to free the memory
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index a48778e1a4ee..b55dacd09e1e 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -58,6 +58,7 @@ pci_epc_interface_string(enum pci_epc_interface_type type)
  * @map_msi_irq: ops to map physical address to MSI address and return MSI data
  * @start: ops to start the PCI link
  * @stop: ops to stop the PCI link
+ * @dmac_transfer: ops to transfer data using internal DMAC
  * @get_features: ops to get the features supported by the EPC
  * @owner: the module owner containing the ops
  */
@@ -86,6 +87,9 @@ struct pci_epc_ops {
 			       u32 *msi_addr_offset);
 	int	(*start)(struct pci_epc *epc);
 	void	(*stop)(struct pci_epc *epc);
+	int	(*dmac_transfer)(struct pci_epc *epc, struct pci_epf *epf,
+				 dma_addr_t dma_dst, dma_addr_t dma_src,
+				 size_t len, enum pci_epf_xfr_direction dir);
 	const struct pci_epc_features* (*get_features)(struct pci_epc *epc,
 						       u8 func_no, u8 vfunc_no);
 	struct module *owner;
@@ -159,6 +163,8 @@ struct pci_epc {
  *			for initialization
  * @msi_capable: indicate if the endpoint function has MSI capability
  * @msix_capable: indicate if the endpoint function has MSI-X capability
+ * @internal_dmac: indicate if the endpoint function has internal DMAC
+ * @internal_dmac_mask: indicates the DMA mask to be applied for the device
  * @reserved_bar: bitmap to indicate reserved BAR unavailable to function driver
  * @bar_fixed_64bit: bitmap to indicate fixed 64bit BARs
  * @bar_fixed_size: Array specifying the size supported by each BAR
@@ -169,6 +175,8 @@ struct pci_epc_features {
 	unsigned int	core_init_notifier : 1;
 	unsigned int	msi_capable : 1;
 	unsigned int	msix_capable : 1;
+	unsigned int	internal_dmac : 1;
+	u64		internal_dmac_mask;
 	u8	reserved_bar;
 	u8	bar_fixed_64bit;
 	u64	bar_fixed_size[PCI_STD_NUM_BARS];
diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
index 009a07147c61..78d661db085d 100644
--- a/include/linux/pci-epf.h
+++ b/include/linux/pci-epf.h
@@ -32,6 +32,11 @@ enum pci_barno {
 	BAR_5,
 };
 
+enum pci_epf_xfr_direction {
+	PCIE_TO_INTERNAL,
+	INTERNAL_TO_PCIE,
+};
+
 /**
  * struct pci_epf_header - represents standard configuration header
  * @vendorid: identifies device manufacturer
@@ -209,6 +214,8 @@ void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
 			enum pci_epc_interface_type type);
 int pci_epf_bind(struct pci_epf *epf);
 void pci_epf_unbind(struct pci_epf *epf);
+int pci_epf_internal_dmac_xfr(struct pci_epf *epf, dma_addr_t dma_dst, dma_addr_t dma_src,
+			      size_t len, enum pci_epf_xfr_direction dir);
 struct config_group *pci_epf_type_add_cfs(struct pci_epf *epf,
 					  struct config_group *group);
 int pci_epf_add_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf);
-- 
2.25.1


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

* [RFC PATCH 2/5] PCI: endpoint: Add support to data transfer using internal dmac
  2022-01-26 19:50 [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC Lad Prabhakar
  2022-01-26 19:50 ` [RFC PATCH 1/5] PCI: endpoint: Add ops and flag to support internal DMAC Lad Prabhakar
@ 2022-01-26 19:50 ` Lad Prabhakar
  2022-02-14  9:49   ` Manivannan Sadhasivam
  2022-01-26 19:50 ` [RFC PATCH 3/5] misc: pci_endpoint_test: Add driver data for Renesas RZ/G2{EHMN} Lad Prabhakar
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 21+ messages in thread
From: Lad Prabhakar @ 2022-01-26 19:50 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Arnd Bergmann, Greg Kroah-Hartman,
	Marek Vasut, Yoshihiro Shimoda, Rob Herring, linux-pci,
	linux-renesas-soc
  Cc: linux-kernel, Prabhakar, Biju Das, Lad Prabhakar

For PCIe EP capable with internal DMAC, transfer data using this
when -d option is used with pcitest.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
 drivers/pci/endpoint/functions/pci-epf-test.c | 184 ++++++++++++++----
 1 file changed, 141 insertions(+), 43 deletions(-)

diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 90d84d3bc868..f792b1a15c44 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -55,6 +55,7 @@ struct pci_epf_test {
 	struct dma_chan		*dma_chan;
 	struct completion	transfer_complete;
 	bool			dma_supported;
+	bool			internal_dmac;
 	const struct pci_epc_features *epc_features;
 };
 
@@ -148,6 +149,40 @@ static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
 	return 0;
 }
 
+/**
+ * pci_epf_test_internal_dmac_data_transfer() - Function that uses internal DMAC
+ *				to transfer data between PCIe EP and remote PCIe RC
+ * @epf_test: the EPF test device that performs the data transfer operation
+ * @dma_dst: The destination address of the data transfer. It can be a physical
+ *	     address given by pci_epc_mem_alloc_addr or DMA mapping APIs.
+ * @dma_src: The source address of the data transfer. It can be a physical
+ *	     address given by pci_epc_mem_alloc_addr or DMA mapping APIs.
+ * @len: The size of the data transfer
+ * @dir: Direction of data transfer
+ *
+ * Function that uses internal dmac supported by the controller to transfer data
+ * between PCIe EP and remote PCIe RC.
+ *
+ * The function returns '0' on success and negative value on failure.
+ */
+static int
+pci_epf_test_internal_dmac_data_transfer(struct pci_epf_test *epf_test,
+					 dma_addr_t dma_dst, dma_addr_t dma_src,
+					 size_t len, enum pci_epf_xfr_direction dir)
+{
+	struct pci_epf *epf = epf_test->epf;
+	int ret;
+
+	if (!epf_test->internal_dmac)
+		return -EINVAL;
+
+	ret = pci_epf_internal_dmac_xfr(epf, dma_dst, dma_src, len, dir);
+	if (ret)
+		return -EIO;
+
+	return 0;
+}
+
 /**
  * pci_epf_test_init_dma_chan() - Function to initialize EPF test DMA channel
  * @epf_test: the EPF test device that performs data transfer operation
@@ -238,6 +273,14 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
 	struct pci_epc *epc = epf->epc;
 	enum pci_barno test_reg_bar = epf_test->test_reg_bar;
 	struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
+	bool internal_dmac = epf_test->internal_dmac;
+
+	use_dma = !!(reg->flags & FLAG_USE_DMA);
+
+	if (use_dma && internal_dmac) {
+		dev_err(dev, "Operation not supported\n");
+		return -EINVAL;
+	}
 
 	src_addr = pci_epc_mem_alloc_addr(epc, &src_phys_addr, reg->size);
 	if (!src_addr) {
@@ -272,7 +315,6 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
 	}
 
 	ktime_get_ts64(&start);
-	use_dma = !!(reg->flags & FLAG_USE_DMA);
 	if (use_dma) {
 		if (!epf_test->dma_supported) {
 			dev_err(dev, "Cannot transfer data using DMA\n");
@@ -322,31 +364,49 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
 	struct device *dma_dev = epf->epc->dev.parent;
 	enum pci_barno test_reg_bar = epf_test->test_reg_bar;
 	struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
+	bool internal_dmac = epf_test->internal_dmac;
 
-	src_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
-	if (!src_addr) {
-		dev_err(dev, "Failed to allocate address\n");
-		reg->status = STATUS_SRC_ADDR_INVALID;
-		ret = -ENOMEM;
-		goto err;
-	}
+	use_dma = !!(reg->flags & FLAG_USE_DMA);
 
-	ret = pci_epc_map_addr(epc, epf->func_no, epf->vfunc_no, phys_addr,
-			       reg->src_addr, reg->size);
-	if (ret) {
-		dev_err(dev, "Failed to map address\n");
-		reg->status = STATUS_SRC_ADDR_INVALID;
-		goto err_addr;
+	if (use_dma && internal_dmac) {
+		phys_addr = reg->src_addr;
+		src_addr = NULL;
+	} else {
+		src_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
+		if (!src_addr) {
+			dev_err(dev, "Failed to allocate address\n");
+			reg->status = STATUS_SRC_ADDR_INVALID;
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		ret = pci_epc_map_addr(epc, epf->func_no, epf->vfunc_no, phys_addr,
+				       reg->src_addr, reg->size);
+		if (ret) {
+			dev_err(dev, "Failed to map address\n");
+			reg->status = STATUS_SRC_ADDR_INVALID;
+			goto err_addr;
+		}
 	}
 
-	buf = kzalloc(reg->size, GFP_KERNEL);
+	if (use_dma && internal_dmac)
+		buf = dma_alloc_coherent(dev, reg->size, &dst_phys_addr, GFP_KERNEL | GFP_DMA);
+	else
+		buf = kzalloc(reg->size, GFP_KERNEL);
 	if (!buf) {
 		ret = -ENOMEM;
 		goto err_map_addr;
 	}
 
-	use_dma = !!(reg->flags & FLAG_USE_DMA);
-	if (use_dma) {
+	if (use_dma && internal_dmac) {
+		ktime_get_ts64(&start);
+		ret = pci_epf_test_internal_dmac_data_transfer(epf_test, dst_phys_addr,
+							       phys_addr, reg->size,
+							       PCIE_TO_INTERNAL);
+		if (ret)
+			dev_err(dev, "Data transfer failed\n");
+		ktime_get_ts64(&end);
+	} else if (use_dma) {
 		if (!epf_test->dma_supported) {
 			dev_err(dev, "Cannot transfer data using DMA\n");
 			ret = -EINVAL;
@@ -383,13 +443,18 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
 		ret = -EIO;
 
 err_dma_map:
-	kfree(buf);
+	if (use_dma && internal_dmac)
+		dma_free_coherent(dev, reg->size, buf, dst_phys_addr);
+	else
+		kfree(buf);
 
 err_map_addr:
-	pci_epc_unmap_addr(epc, epf->func_no, epf->vfunc_no, phys_addr);
+	if (!(use_dma && internal_dmac))
+		pci_epc_unmap_addr(epc, epf->func_no, epf->vfunc_no, phys_addr);
 
 err_addr:
-	pci_epc_mem_free_addr(epc, phys_addr, src_addr, reg->size);
+	if (!(use_dma && internal_dmac))
+		pci_epc_mem_free_addr(epc, phys_addr, src_addr, reg->size);
 
 err:
 	return ret;
@@ -410,24 +475,36 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
 	struct device *dma_dev = epf->epc->dev.parent;
 	enum pci_barno test_reg_bar = epf_test->test_reg_bar;
 	struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
+	bool internal_dmac = epf_test->internal_dmac;
 
-	dst_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
-	if (!dst_addr) {
-		dev_err(dev, "Failed to allocate address\n");
-		reg->status = STATUS_DST_ADDR_INVALID;
-		ret = -ENOMEM;
-		goto err;
-	}
+	use_dma = !!(reg->flags & FLAG_USE_DMA);
 
-	ret = pci_epc_map_addr(epc, epf->func_no, epf->vfunc_no, phys_addr,
-			       reg->dst_addr, reg->size);
-	if (ret) {
-		dev_err(dev, "Failed to map address\n");
-		reg->status = STATUS_DST_ADDR_INVALID;
-		goto err_addr;
+	if (use_dma && internal_dmac) {
+		phys_addr = reg->dst_addr;
+		dst_addr = NULL;
+	} else {
+		dst_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
+		if (!dst_addr) {
+			dev_err(dev, "Failed to allocate address\n");
+			reg->status = STATUS_DST_ADDR_INVALID;
+			ret = -ENOMEM;
+			goto err;
+		}
+
+		ret = pci_epc_map_addr(epc, epf->func_no, epf->vfunc_no, phys_addr,
+				       reg->dst_addr, reg->size);
+		if (ret) {
+			dev_err(dev, "Failed to map address\n");
+			reg->status = STATUS_DST_ADDR_INVALID;
+			goto err_addr;
+		}
 	}
 
-	buf = kzalloc(reg->size, GFP_KERNEL);
+	if (use_dma && internal_dmac)
+		buf = dma_alloc_coherent(dev, reg->size,
+					 &src_phys_addr, GFP_KERNEL | GFP_DMA);
+	else
+		buf = kzalloc(reg->size, GFP_KERNEL);
 	if (!buf) {
 		ret = -ENOMEM;
 		goto err_map_addr;
@@ -436,8 +513,15 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
 	get_random_bytes(buf, reg->size);
 	reg->checksum = crc32_le(~0, buf, reg->size);
 
-	use_dma = !!(reg->flags & FLAG_USE_DMA);
-	if (use_dma) {
+	if (use_dma && internal_dmac) {
+		ktime_get_ts64(&start);
+		ret = pci_epf_test_internal_dmac_data_transfer(epf_test, phys_addr,
+							       src_phys_addr, reg->size,
+							       INTERNAL_TO_PCIE);
+		if (ret)
+			dev_err(dev, "Data transfer failed\n");
+		ktime_get_ts64(&end);
+	} else if (use_dma) {
 		if (!epf_test->dma_supported) {
 			dev_err(dev, "Cannot transfer data using DMA\n");
 			ret = -EINVAL;
@@ -476,13 +560,18 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
 	usleep_range(1000, 2000);
 
 err_dma_map:
-	kfree(buf);
+	if (use_dma && internal_dmac)
+		dma_free_coherent(dev, reg->size, buf, src_phys_addr);
+	else
+		kfree(buf);
 
 err_map_addr:
-	pci_epc_unmap_addr(epc, epf->func_no, epf->vfunc_no, phys_addr);
+	if (!(use_dma && internal_dmac))
+		pci_epc_unmap_addr(epc, epf->func_no, epf->vfunc_no, phys_addr);
 
 err_addr:
-	pci_epc_mem_free_addr(epc, phys_addr, dst_addr, reg->size);
+	if (!(use_dma && internal_dmac))
+		pci_epc_mem_free_addr(epc, phys_addr, dst_addr, reg->size);
 
 err:
 	return ret;
@@ -838,6 +927,7 @@ static int pci_epf_test_bind(struct pci_epf *epf)
 	struct pci_epc *epc = epf->epc;
 	bool linkup_notifier = false;
 	bool core_init_notifier = false;
+	struct device *dev = &epf->dev;
 
 	if (WARN_ON_ONCE(!epc))
 		return -EINVAL;
@@ -857,6 +947,12 @@ static int pci_epf_test_bind(struct pci_epf *epf)
 
 	epf_test->test_reg_bar = test_reg_bar;
 	epf_test->epc_features = epc_features;
+	epf_test->internal_dmac = epc_features->internal_dmac;
+	if (epf_test->internal_dmac && epc_features->internal_dmac_mask) {
+		ret = dma_set_coherent_mask(dev, epc_features->internal_dmac_mask);
+		if (ret)
+			return ret;
+	}
 
 	ret = pci_epf_test_alloc_space(epf);
 	if (ret)
@@ -868,11 +964,13 @@ static int pci_epf_test_bind(struct pci_epf *epf)
 			return ret;
 	}
 
-	epf_test->dma_supported = true;
+	epf_test->dma_supported = false;
 
-	ret = pci_epf_test_init_dma_chan(epf_test);
-	if (ret)
-		epf_test->dma_supported = false;
+	if (!epf_test->internal_dmac) {
+		ret = pci_epf_test_init_dma_chan(epf_test);
+		if (!ret)
+			epf_test->dma_supported = true;
+	}
 
 	if (linkup_notifier) {
 		epf->nb.notifier_call = pci_epf_test_notifier;
-- 
2.25.1


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

* [RFC PATCH 3/5] misc: pci_endpoint_test: Add driver data for Renesas RZ/G2{EHMN}
  2022-01-26 19:50 [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC Lad Prabhakar
  2022-01-26 19:50 ` [RFC PATCH 1/5] PCI: endpoint: Add ops and flag to support internal DMAC Lad Prabhakar
  2022-01-26 19:50 ` [RFC PATCH 2/5] PCI: endpoint: Add support to data transfer using internal dmac Lad Prabhakar
@ 2022-01-26 19:50 ` Lad Prabhakar
  2022-02-14 10:02   ` Manivannan Sadhasivam
  2022-01-26 19:50 ` [RFC PATCH 4/5] misc: pci_endpoint_test: Add support to pass flags for buffer allocation Lad Prabhakar
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 21+ messages in thread
From: Lad Prabhakar @ 2022-01-26 19:50 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Arnd Bergmann, Greg Kroah-Hartman,
	Marek Vasut, Yoshihiro Shimoda, Rob Herring, linux-pci,
	linux-renesas-soc
  Cc: linux-kernel, Prabhakar, Biju Das, Lad Prabhakar

Add "dmac_data_alignment" member (indicating the alignment requirement
for internal DMAC for data transfers) to struct pci_endpoint_test_data
and add driver_data to Renesas RZ/G2{EHMN}.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
 drivers/misc/pci_endpoint_test.c | 40 ++++++++++++++++++++++++++------
 1 file changed, 33 insertions(+), 7 deletions(-)

diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 8f786a225dcf..0a00d45830e9 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -116,6 +116,7 @@ struct pci_endpoint_test {
 	struct miscdevice miscdev;
 	enum pci_barno test_reg_bar;
 	size_t alignment;
+	size_t dmac_data_alignment;
 	const char *name;
 };
 
@@ -123,6 +124,7 @@ struct pci_endpoint_test_data {
 	enum pci_barno test_reg_bar;
 	size_t alignment;
 	int irq_type;
+	size_t dmac_data_alignment;
 };
 
 static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test,
@@ -368,8 +370,11 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
 		goto err;
 
 	use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
-	if (use_dma)
+	if (use_dma) {
 		flags |= FLAG_USE_DMA;
+		if (test->dmac_data_alignment)
+			size =  ALIGN(size, test->dmac_data_alignment);
+	}
 
 	if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
 		dev_err(dev, "Invalid IRQ type option\n");
@@ -502,8 +507,11 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
 		goto err;
 
 	use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
-	if (use_dma)
+	if (use_dma) {
 		flags |= FLAG_USE_DMA;
+		if (test->dmac_data_alignment)
+			size =  ALIGN(size, test->dmac_data_alignment);
+	}
 
 	if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
 		dev_err(dev, "Invalid IRQ type option\n");
@@ -600,8 +608,11 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
 		goto err;
 
 	use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
-	if (use_dma)
+	if (use_dma) {
 		flags |= FLAG_USE_DMA;
+		if (test->dmac_data_alignment)
+			size =  ALIGN(size, test->dmac_data_alignment);
+	}
 
 	if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
 		dev_err(dev, "Invalid IRQ type option\n");
@@ -787,6 +798,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
 		test->test_reg_bar = test_reg_bar;
 		test->alignment = data->alignment;
 		irq_type = data->irq_type;
+		test->dmac_data_alignment = data->dmac_data_alignment;
 	}
 
 	init_completion(&test->irq_raised);
@@ -948,6 +960,12 @@ static const struct pci_endpoint_test_data j721e_data = {
 	.irq_type = IRQ_TYPE_MSI,
 };
 
+static const struct pci_endpoint_test_data renesas_rzg2x_data = {
+	.test_reg_bar = BAR_0,
+	.irq_type = IRQ_TYPE_MSI,
+	.dmac_data_alignment = 8,
+};
+
 static const struct pci_device_id pci_endpoint_test_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x),
 	  .driver_data = (kernel_ulong_t)&default_data,
@@ -965,10 +983,18 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
 	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
 	  .driver_data = (kernel_ulong_t)&am654_data
 	},
-	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774A1),},
-	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774B1),},
-	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774C0),},
-	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774E1),},
+	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774A1),
+	 .driver_data = (kernel_ulong_t)&renesas_rzg2x_data,
+	},
+	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774B1),
+	 .driver_data = (kernel_ulong_t)&renesas_rzg2x_data,
+	},
+	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774C0),
+	 .driver_data = (kernel_ulong_t)&renesas_rzg2x_data,
+	},
+	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774E1),
+	 .driver_data = (kernel_ulong_t)&renesas_rzg2x_data,
+	},
 	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
 	  .driver_data = (kernel_ulong_t)&j721e_data,
 	},
-- 
2.25.1


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

* [RFC PATCH 4/5] misc: pci_endpoint_test: Add support to pass flags for buffer allocation
  2022-01-26 19:50 [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC Lad Prabhakar
                   ` (2 preceding siblings ...)
  2022-01-26 19:50 ` [RFC PATCH 3/5] misc: pci_endpoint_test: Add driver data for Renesas RZ/G2{EHMN} Lad Prabhakar
@ 2022-01-26 19:50 ` Lad Prabhakar
  2022-02-14 10:11   ` Manivannan Sadhasivam
  2022-01-26 19:50 ` [RFC PATCH 5/5] PCI: rcar-ep: Add support for DMAC Lad Prabhakar
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 21+ messages in thread
From: Lad Prabhakar @ 2022-01-26 19:50 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Arnd Bergmann, Greg Kroah-Hartman,
	Marek Vasut, Yoshihiro Shimoda, Rob Herring, linux-pci,
	linux-renesas-soc
  Cc: linux-kernel, Prabhakar, Biju Das, Lad Prabhakar

By default GFP_KERNEL flag is used for buffer allocation in read, write
and copy test and then later mapped using streaming DMA api. But on
Renesas RZ/G2{EHMN} platforms using the default flag causes the tests to
fail. Allocating the buffers from DMA zone (using the GFP_DMA flag) make
the test cases to pass.

To handle such case add flags as part of struct pci_endpoint_test_data
so that platforms can pass the required flags based on the requirement.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
Hi All,

This patch is based on the conversation where switching to streaming
DMA api causes read/write/copy tests to fail on Renesas RZ/G2 platforms
when buffers are allocated using GFP_KERNEL.

[0] https://www.spinics.net/lists/linux-pci/msg92385.html

Cheers,
Prabhakar
---
 drivers/misc/pci_endpoint_test.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 0a00d45830e9..974546992c5e 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -117,6 +117,7 @@ struct pci_endpoint_test {
 	enum pci_barno test_reg_bar;
 	size_t alignment;
 	size_t dmac_data_alignment;
+	gfp_t flags;
 	const char *name;
 };
 
@@ -125,6 +126,7 @@ struct pci_endpoint_test_data {
 	size_t alignment;
 	int irq_type;
 	size_t dmac_data_alignment;
+	gfp_t flags;
 };
 
 static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test,
@@ -381,7 +383,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
 		goto err;
 	}
 
-	orig_src_addr = kzalloc(size + alignment, GFP_KERNEL);
+	orig_src_addr = kzalloc(size + alignment, test->flags);
 	if (!orig_src_addr) {
 		dev_err(dev, "Failed to allocate source buffer\n");
 		ret = false;
@@ -414,7 +416,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
 
 	src_crc32 = crc32_le(~0, src_addr, size);
 
-	orig_dst_addr = kzalloc(size + alignment, GFP_KERNEL);
+	orig_dst_addr = kzalloc(size + alignment, test->flags);
 	if (!orig_dst_addr) {
 		dev_err(dev, "Failed to allocate destination address\n");
 		ret = false;
@@ -518,7 +520,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
 		goto err;
 	}
 
-	orig_addr = kzalloc(size + alignment, GFP_KERNEL);
+	orig_addr = kzalloc(size + alignment, test->flags);
 	if (!orig_addr) {
 		dev_err(dev, "Failed to allocate address\n");
 		ret = false;
@@ -619,7 +621,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
 		goto err;
 	}
 
-	orig_addr = kzalloc(size + alignment, GFP_KERNEL);
+	orig_addr = kzalloc(size + alignment, test->flags);
 	if (!orig_addr) {
 		dev_err(dev, "Failed to allocate destination address\n");
 		ret = false;
@@ -788,6 +790,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
 	test->alignment = 0;
 	test->pdev = pdev;
 	test->irq_type = IRQ_TYPE_UNDEFINED;
+	test->flags = GFP_KERNEL;
 
 	if (no_msi)
 		irq_type = IRQ_TYPE_LEGACY;
@@ -799,6 +802,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
 		test->alignment = data->alignment;
 		irq_type = data->irq_type;
 		test->dmac_data_alignment = data->dmac_data_alignment;
+		test->flags = data->flags;
 	}
 
 	init_completion(&test->irq_raised);
@@ -947,23 +951,27 @@ static const struct pci_endpoint_test_data default_data = {
 	.test_reg_bar = BAR_0,
 	.alignment = SZ_4K,
 	.irq_type = IRQ_TYPE_MSI,
+	.flags = GFP_KERNEL,
 };
 
 static const struct pci_endpoint_test_data am654_data = {
 	.test_reg_bar = BAR_2,
 	.alignment = SZ_64K,
 	.irq_type = IRQ_TYPE_MSI,
+	.flags = GFP_KERNEL,
 };
 
 static const struct pci_endpoint_test_data j721e_data = {
 	.alignment = 256,
 	.irq_type = IRQ_TYPE_MSI,
+	.flags = GFP_KERNEL,
 };
 
 static const struct pci_endpoint_test_data renesas_rzg2x_data = {
 	.test_reg_bar = BAR_0,
 	.irq_type = IRQ_TYPE_MSI,
 	.dmac_data_alignment = 8,
+	.flags = GFP_KERNEL | GFP_DMA,
 };
 
 static const struct pci_device_id pci_endpoint_test_tbl[] = {
-- 
2.25.1


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

* [RFC PATCH 5/5] PCI: rcar-ep: Add support for DMAC
  2022-01-26 19:50 [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC Lad Prabhakar
                   ` (3 preceding siblings ...)
  2022-01-26 19:50 ` [RFC PATCH 4/5] misc: pci_endpoint_test: Add support to pass flags for buffer allocation Lad Prabhakar
@ 2022-01-26 19:50 ` Lad Prabhakar
  2022-02-14 10:40   ` Manivannan Sadhasivam
  2022-02-21  4:32   ` [EXT] " Li Chen
  2022-02-09  4:47 ` [EXT] [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC Li Chen
  2022-02-10  8:40 ` Manivannan Sadhasivam
  6 siblings, 2 replies; 21+ messages in thread
From: Lad Prabhakar @ 2022-01-26 19:50 UTC (permalink / raw)
  To: Kishon Vijay Abraham I, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Arnd Bergmann, Greg Kroah-Hartman,
	Marek Vasut, Yoshihiro Shimoda, Rob Herring, linux-pci,
	linux-renesas-soc
  Cc: linux-kernel, Prabhakar, Biju Das, Lad Prabhakar

R-Car PCIe controller has an internal DMAC to support data transfer
between Internal Bus -> PCI Express and vice versa.

This patch fills in the required flags and ops for the PCIe EP to
support DMAC transfer.

Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
---
 drivers/pci/controller/pcie-rcar-ep.c | 227 ++++++++++++++++++++++++++
 drivers/pci/controller/pcie-rcar.h    |  23 +++
 2 files changed, 250 insertions(+)

diff --git a/drivers/pci/controller/pcie-rcar-ep.c b/drivers/pci/controller/pcie-rcar-ep.c
index f9682df1da61..c49b25069328 100644
--- a/drivers/pci/controller/pcie-rcar-ep.c
+++ b/drivers/pci/controller/pcie-rcar-ep.c
@@ -18,6 +18,21 @@
 
 #define RCAR_EPC_MAX_FUNCTIONS		1
 
+#define RCAR_PCIE_MAX_DMAC_BYTE_COUNT		0x7FFFFFFU
+#define RCAR_PCIE_DMAC_BYTE_COUNT_MULTIPLE	8
+#define RCAR_PCIE_DMAC_TIMEOUT			(msecs_to_jiffies(3 * 1000))
+#define RCAR_PCIE_DMAC_DEFAULT_CHANNEL		0
+
+enum rcar_pcie_ep_dmac_xfr_status {
+	RCAR_PCIE_DMA_XFR_SUCCESS,
+	RCAR_PCIE_DMA_XFR_ERROR,
+};
+
+struct rcar_pcie_ep_dmac_info {
+	enum rcar_pcie_ep_dmac_xfr_status status;
+	size_t bytes;
+};
+
 /* Structure representing the PCIe interface */
 struct rcar_pcie_endpoint {
 	struct rcar_pcie	pcie;
@@ -28,8 +43,114 @@ struct rcar_pcie_endpoint {
 	unsigned long		*ib_window_map;
 	u32			num_ib_windows;
 	u32			num_ob_windows;
+	struct completion	irq_raised;
+	struct mutex		dma_operation;
+	spinlock_t		lock;
+	struct rcar_pcie_ep_dmac_info xfr;
 };
 
+static inline bool rcar_pcie_ep_is_dmac_active(struct rcar_pcie_endpoint *ep)
+{
+	if (rcar_pci_read_reg(&ep->pcie, PCIEDMAOR) & PCIEDMAOR_DMAACT)
+		return true;
+
+	return false;
+}
+
+static void
+rcar_pcie_ep_setup_dmac_request(struct rcar_pcie_endpoint *ep,
+				dma_addr_t dma_dst, dma_addr_t dma_src,
+				size_t len, enum pci_epf_xfr_direction dir, u8 ch)
+{
+	struct rcar_pcie *pcie = &ep->pcie;
+	u32 val;
+
+	ep->xfr.status = RCAR_PCIE_DMA_XFR_ERROR;
+	ep->xfr.bytes = RCAR_PCIE_MAX_DMAC_BYTE_COUNT;
+
+	/* swap values if xfr is from pcie to internal */
+	if (dir == PCIE_TO_INTERNAL)
+		swap(dma_dst, dma_src);
+
+	/* Configure the PCI Express lower */
+	rcar_pci_write_reg(pcie, lower_32_bits(dma_dst), PCIEDMPALR(ch));
+
+	/* Configure the PCI Express upper */
+	rcar_pci_write_reg(pcie, upper_32_bits(dma_dst), PCIEDMPAUR(ch));
+
+	/* Configure the internal bus address */
+	rcar_pci_write_reg(pcie, lower_32_bits(dma_src), PCIEDMIAR(ch));
+
+	/* Configure the byte count values */
+	rcar_pci_write_reg(pcie, len, PCIEDMBCNTR(ch));
+
+	/* Enable interrupts */
+	val = rcar_pci_read_reg(pcie, PCIEDMCHSR(ch));
+
+	/* set enable flags */
+	val |= PCIEDMCHSR_IE;
+	val |= PCIEDMCHSR_IBEE;
+	val |= PCIEDMCHSR_PEEE;
+	val |= PCIEDMCHSR_CHTCE;
+
+	/* Clear error flags */
+	val &= ~PCIEDMCHSR_TE;
+	val &= ~PCIEDMCHSR_PEE;
+	val &= ~PCIEDMCHSR_IBE;
+	val &= ~PCIEDMCHSR_CHTC;
+
+	rcar_pci_write_reg(pcie, val, PCIEDMCHSR(ch));
+
+	wmb(); /* flush the settings */
+}
+
+static void rcar_pcie_ep_execute_dmac_request(struct rcar_pcie_endpoint *ep,
+					      enum pci_epf_xfr_direction dir, u8 ch)
+{
+	struct rcar_pcie *pcie = &ep->pcie;
+	u32 val;
+
+	/* Enable DMA */
+	val = rcar_pci_read_reg(pcie, PCIEDMAOR);
+	val |= PCIEDMAOR_DMAE;
+	rcar_pci_write_reg(pcie, val, PCIEDMAOR);
+
+	/* Configure the DMA direction */
+	val = rcar_pci_read_reg(pcie, PCIEDMCHCR(ch));
+	if (dir == INTERNAL_TO_PCIE)
+		val |= PCIEDMCHCR_DIR;
+	else
+		val &= ~PCIEDMCHCR_DIR;
+
+	val |= PCIEDMCHCR_CHE;
+	rcar_pci_write_reg(pcie, val, PCIEDMCHCR(ch));
+
+	wmb(); /* flush the settings */
+}
+
+static enum rcar_pcie_ep_dmac_xfr_status
+rcar_pcie_ep_get_dmac_status(struct rcar_pcie_endpoint *ep,
+			     size_t *count, u8 ch)
+{
+	*count = ep->xfr.bytes;
+	return ep->xfr.status;
+}
+
+static void rcar_pcie_ep_stop_dmac_request(struct rcar_pcie_endpoint *ep, u8 ch)
+{
+	struct rcar_pcie *pcie = &ep->pcie;
+	u32 val;
+
+	val = rcar_pci_read_reg(pcie, PCIEDMCHCR(ch));
+	val &= ~PCIEDMCHCR_CHE;
+	rcar_pci_write_reg(pcie, val, PCIEDMCHCR(ch));
+
+	/* Disable interrupt */
+	val = rcar_pci_read_reg(pcie, PCIEDMAOR);
+	val &= ~PCIEDMAOR_DMAE;
+	rcar_pci_write_reg(pcie, val, PCIEDMAOR);
+}
+
 static void rcar_pcie_ep_hw_init(struct rcar_pcie *pcie)
 {
 	u32 val;
@@ -419,6 +540,44 @@ static int rcar_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, u8 vfn,
 	}
 }
 
+static int rcar_pcie_ep_data_transfer(struct pci_epc *epc, struct pci_epf *epf,
+				      dma_addr_t dma_dst, dma_addr_t dma_src,
+				      size_t len, enum pci_epf_xfr_direction dir)
+{
+	struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
+	u8 ch = RCAR_PCIE_DMAC_DEFAULT_CHANNEL;
+	enum rcar_pcie_ep_dmac_xfr_status stat;
+	int ret = -EINVAL;
+	long wait_status;
+	size_t count;
+
+	if (len > RCAR_PCIE_MAX_DMAC_BYTE_COUNT ||
+	    (len % RCAR_PCIE_DMAC_BYTE_COUNT_MULTIPLE) != 0)
+		return -EINVAL;
+
+	if (mutex_is_locked(&ep->dma_operation) || rcar_pcie_ep_is_dmac_active(ep))
+		return -EBUSY;
+
+	mutex_lock(&ep->dma_operation);
+
+	rcar_pcie_ep_setup_dmac_request(ep, dma_dst, dma_src, len, dir, ch);
+
+	rcar_pcie_ep_execute_dmac_request(ep, dir, ch);
+
+	wait_status = wait_for_completion_interruptible_timeout(&ep->irq_raised,
+								RCAR_PCIE_DMAC_TIMEOUT);
+	if (wait_status <= 0) {
+		rcar_pcie_ep_stop_dmac_request(ep, ch);
+	} else {
+		stat = rcar_pcie_ep_get_dmac_status(ep, &count, ch);
+		if (stat == RCAR_PCIE_DMA_XFR_SUCCESS && !count)
+			ret = 0;
+	}
+
+	mutex_unlock(&ep->dma_operation);
+	return ret;
+}
+
 static int rcar_pcie_ep_start(struct pci_epc *epc)
 {
 	struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
@@ -429,6 +588,55 @@ static int rcar_pcie_ep_start(struct pci_epc *epc)
 	return 0;
 }
 
+static irqreturn_t rcar_pcie_ep_dmac_irq_handler(int irq, void *arg)
+{
+	u8 ch = RCAR_PCIE_DMAC_DEFAULT_CHANNEL;
+	struct rcar_pcie_endpoint *ep = arg;
+	struct rcar_pcie *pcie = &ep->pcie;
+	unsigned long flags;
+	u32 chsr_val;
+	u32 chcr_val;
+	u32 bytes;
+
+	spin_lock_irqsave(&ep->lock, flags);
+
+	chsr_val = rcar_pci_read_reg(pcie, PCIEDMCHSR(ch));
+
+	chcr_val = rcar_pci_read_reg(pcie, PCIEDMCHCR(ch));
+
+	if (mutex_is_locked(&ep->dma_operation)) {
+		if ((chsr_val &  PCIEDMCHSR_PEE) ||
+		    (chsr_val & PCIEDMCHSR_IBE) ||
+		    (chsr_val & PCIEDMCHSR_CHTC))
+			ep->xfr.status = RCAR_PCIE_DMA_XFR_ERROR;
+		else if (chsr_val & PCIEDMCHSR_TE)
+			ep->xfr.status = RCAR_PCIE_DMA_XFR_SUCCESS;
+
+		/* get byte count */
+		bytes = rcar_pci_read_reg(pcie, PCIEDMBCNTR(ch));
+		ep->xfr.bytes = bytes;
+
+		if ((chsr_val & PCIEDMCHSR_PEE) || (chsr_val & PCIEDMCHSR_IBE) ||
+		    (chsr_val & PCIEDMCHSR_TE) || (chsr_val & PCIEDMCHSR_CHTC)) {
+			complete(&ep->irq_raised);
+		}
+	} else {
+		spin_unlock_irqrestore(&ep->lock, flags);
+		return IRQ_NONE;
+	}
+
+	if (chcr_val & PCIEDMCHCR_CHE)
+		chcr_val &= ~PCIEDMCHCR_CHE;
+	rcar_pci_write_reg(pcie, chcr_val, PCIEDMCHCR(ch));
+
+	/* Clear DMA interrupt source */
+	rcar_pci_write_reg(pcie, chsr_val, PCIEDMCHSR(ch));
+
+	spin_unlock_irqrestore(&ep->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
 static void rcar_pcie_ep_stop(struct pci_epc *epc)
 {
 	struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
@@ -446,6 +654,8 @@ static const struct pci_epc_features rcar_pcie_epc_features = {
 	.bar_fixed_size[0] = 128,
 	.bar_fixed_size[2] = 256,
 	.bar_fixed_size[4] = 256,
+	.internal_dmac = true,
+	.internal_dmac_mask = DMA_BIT_MASK(32),
 };
 
 static const struct pci_epc_features*
@@ -466,6 +676,7 @@ static const struct pci_epc_ops rcar_pcie_epc_ops = {
 	.start		= rcar_pcie_ep_start,
 	.stop		= rcar_pcie_ep_stop,
 	.get_features	= rcar_pcie_ep_get_features,
+	.dmac_transfer	= rcar_pcie_ep_data_transfer,
 };
 
 static const struct of_device_id rcar_pcie_ep_of_match[] = {
@@ -480,6 +691,7 @@ static int rcar_pcie_ep_probe(struct platform_device *pdev)
 	struct rcar_pcie_endpoint *ep;
 	struct rcar_pcie *pcie;
 	struct pci_epc *epc;
+	int dmac_irq;
 	int err;
 
 	ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
@@ -502,6 +714,14 @@ static int rcar_pcie_ep_probe(struct platform_device *pdev)
 		goto err_pm_put;
 	}
 
+	dmac_irq = platform_get_irq(pdev, 1);
+	if (dmac_irq < 0)
+		goto err_pm_put;
+
+	init_completion(&ep->irq_raised);
+	mutex_init(&ep->dma_operation);
+	spin_lock_init(&ep->lock);
+
 	ep->num_ib_windows = MAX_NR_INBOUND_MAPS;
 	ep->ib_window_map =
 			devm_kcalloc(dev, BITS_TO_LONGS(ep->num_ib_windows),
@@ -533,6 +753,13 @@ static int rcar_pcie_ep_probe(struct platform_device *pdev)
 
 	rcar_pcie_ep_hw_init(pcie);
 
+	err = devm_request_irq(dev, dmac_irq, rcar_pcie_ep_dmac_irq_handler,
+			       0, "pcie-rcar-ep-dmac", pcie);
+	if (err) {
+		dev_err(dev, "failed to request dmac irq\n");
+		goto err_pm_put;
+	}
+
 	err = pci_epc_multi_mem_init(epc, ep->ob_window, ep->num_ob_windows);
 	if (err < 0) {
 		dev_err(dev, "failed to initialize the epc memory space\n");
diff --git a/drivers/pci/controller/pcie-rcar.h b/drivers/pci/controller/pcie-rcar.h
index 9bb125db85c6..874f8a384e6d 100644
--- a/drivers/pci/controller/pcie-rcar.h
+++ b/drivers/pci/controller/pcie-rcar.h
@@ -54,6 +54,29 @@
 #define  PAR_ENABLE		BIT(31)
 #define  IO_SPACE		BIT(8)
 
+/* PCIe DMAC control reg & mask */
+#define PCIEDMAOR		0x04000
+#define  PCIEDMAOR_DMAE		BIT(31)
+#define  PCIEDMAOR_DMAACT	BIT(16)
+#define PCIEDMPALR(x)		(0x04100 + ((x) * 0x40))
+#define PCIEDMPAUR(x)		(0x04104 + ((x) * 0x40))
+#define PCIEDMIAR(x)		(0x04108 + ((x) * 0x40))
+#define PCIEDMBCNTR(x)		(0x04110 + ((x) * 0x40))
+#define PCIEDMCCAR(x)		(0x04120 + ((x) * 0x40))
+#define PCIEDMCHCR(x)		(0x04128 + ((x) * 0x40))
+#define  PCIEDMCHCR_CHE		BIT(31)
+#define  PCIEDMCHCR_DIR		BIT(30)
+#define PCIEDMCHSR(x)		(0x0412c + ((x) * 0x40))
+#define  PCIEDMCHSR_CHTCE	BIT(28)
+#define  PCIEDMCHSR_PEEE	BIT(27)
+#define  PCIEDMCHSR_IBEE	BIT(25)
+#define  PCIEDMCHSR_CHTC	BIT(12)
+#define  PCIEDMCHSR_PEE		BIT(11)
+#define  PCIEDMCHSR_IBE		BIT(9)
+#define  PCIEDMCHSR_IE		BIT(3)
+#define  PCIEDMCHSR_TE		BIT(0)
+#define PCIEDMCHC2R(x)		(0x04130 + ((x) * 0x40))
+
 /* Configuration */
 #define PCICONF(x)		(0x010000 + ((x) * 0x4))
 #define  INTDIS			BIT(10)
-- 
2.25.1


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

* RE: [EXT] [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC
  2022-01-26 19:50 [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC Lad Prabhakar
                   ` (4 preceding siblings ...)
  2022-01-26 19:50 ` [RFC PATCH 5/5] PCI: rcar-ep: Add support for DMAC Lad Prabhakar
@ 2022-02-09  4:47 ` Li Chen
  2022-02-09  8:52   ` Lad, Prabhakar
  2022-02-10  8:40 ` Manivannan Sadhasivam
  6 siblings, 1 reply; 21+ messages in thread
From: Li Chen @ 2022-02-09  4:47 UTC (permalink / raw)
  To: Lad Prabhakar, Kishon Vijay Abraham I, Bjorn Helgaas,
	Lorenzo Pieralisi, Krzysztof Wilczyński, Arnd Bergmann,
	Greg Kroah-Hartman, Marek Vasut, Yoshihiro Shimoda, Rob Herring,
	linux-pci, linux-renesas-soc
  Cc: linux-kernel, Prabhakar, Biju Das

Hi Prabhakar,

> [0] https://urldefense.com/v3/__https://www.spinics.net/lists/linux-
> pci/msg92385.html__;!!PeEy7nZLVv0!yP0WqYs165riCjWRhZprjgMVVLfQLtkkPfv_
> R7XCoqkqgMsOyor90EZp0YAdxu0$

Can your streaming DMA test case(-d) pass if you use EP's internal DMAC instead of external DMAC?

Regards,
Li

**********************************************************************
This email and attachments contain Ambarella Proprietary and/or Confidential Information and is intended solely for the use of the individual(s) to whom it is addressed. Any unauthorized review, use, disclosure, distribute, copy, or print is prohibited. If you are not an intended recipient, please contact the sender by reply email and destroy all copies of the original message. Thank you.

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

* Re: [EXT] [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC
  2022-02-09  4:47 ` [EXT] [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC Li Chen
@ 2022-02-09  8:52   ` Lad, Prabhakar
  2022-02-10  5:54     ` Li Chen
  0 siblings, 1 reply; 21+ messages in thread
From: Lad, Prabhakar @ 2022-02-09  8:52 UTC (permalink / raw)
  To: Li Chen
  Cc: Lad Prabhakar, Kishon Vijay Abraham I, Bjorn Helgaas,
	Lorenzo Pieralisi, Krzysztof Wilczyński, Arnd Bergmann,
	Greg Kroah-Hartman, Marek Vasut, Yoshihiro Shimoda, Rob Herring,
	linux-pci, linux-renesas-soc, linux-kernel, Biju Das

Hi Chen-san,

On Wed, Feb 9, 2022 at 4:48 AM Li Chen <lchen@ambarella.com> wrote:
>
> Hi Prabhakar,
>
> > [0] https://urldefense.com/v3/__https://www.spinics.net/lists/linux-
> > pci/msg92385.html__;!!PeEy7nZLVv0!yP0WqYs165riCjWRhZprjgMVVLfQLtkkPfv_
> > R7XCoqkqgMsOyor90EZp0YAdxu0$
>
> Can your streaming DMA test case(-d) pass if you use EP's internal DMAC instead of external DMAC?
>
Sorry I don't quite get you here.

This patch series adds support for EP to transfer using internal DMAC
as no external DMAC is supported, so when "-d" option is passed and if
EP has registered it has internal dmac it will use the same and run
the pcitest.

Cheers,
Prabhakar

> Regards,
> Li
>
> **********************************************************************
> This email and attachments contain Ambarella Proprietary and/or Confidential Information and is intended solely for the use of the individual(s) to whom it is addressed. Any unauthorized review, use, disclosure, distribute, copy, or print is prohibited. If you are not an intended recipient, please contact the sender by reply email and destroy all copies of the original message. Thank you.

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

* RE: [EXT] [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC
  2022-02-09  8:52   ` Lad, Prabhakar
@ 2022-02-10  5:54     ` Li Chen
  2022-02-10  7:47       ` Greg Kroah-Hartman
  0 siblings, 1 reply; 21+ messages in thread
From: Li Chen @ 2022-02-10  5:54 UTC (permalink / raw)
  To: Lad, Prabhakar
  Cc: Lad Prabhakar, Kishon Vijay Abraham I, Bjorn Helgaas,
	Lorenzo Pieralisi, Krzysztof Wilczyński, Arnd Bergmann,
	Greg Kroah-Hartman, Marek Vasut, Yoshihiro Shimoda, Rob Herring,
	linux-pci, linux-renesas-soc, linux-kernel, Biju Das

Hi Prabhakar,

> -----Original Message-----
> From: Lad, Prabhakar [mailto:prabhakar.csengg@gmail.com]
> Sent: Wednesday, February 9, 2022 4:53 PM
> To: Li Chen
> Cc: Lad Prabhakar; Kishon Vijay Abraham I; Bjorn Helgaas; Lorenzo Pieralisi;
> Krzysztof Wilczyński; Arnd Bergmann; Greg Kroah-Hartman; Marek Vasut;
> Yoshihiro Shimoda; Rob Herring; linux-pci@vger.kernel.org; linux-renesas-
> soc@vger.kernel.org; linux-kernel@vger.kernel.org; Biju Das
> Subject: Re: [EXT] [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling
> and driver update for R-Car PCIe EP to support DMAC
> 
> Hi Chen-san,
> 
> On Wed, Feb 9, 2022 at 4:48 AM Li Chen <lchen@ambarella.com> wrote:
> >
> > Hi Prabhakar,
> >
> > > [0] https://urldefense.com/v3/__https://www.spinics.net/lists/linux-
> > >
> pci/msg92385.html__;!!PeEy7nZLVv0!yP0WqYs165riCjWRhZprjgMVVLfQLtkkPfv_
> > > R7XCoqkqgMsOyor90EZp0YAdxu0$
> >
> > Can your streaming DMA test case(-d) pass if you use EP's internal DMAC
> instead of external DMAC?
> >
> Sorry I don't quite get you here.
> 
> This patch series adds support for EP to transfer using internal DMAC
> as no external DMAC is supported, so when "-d" option is passed and if
> EP has registered it has internal dmac it will use the same and run
> the pcitest.

Ok, in my case, read/write via external DMAC always get incorrect data, but read via internal DMAC is correct. Maybe this is our RTL's issue.

Regards,
Li

**********************************************************************
This email and attachments contain Ambarella Proprietary and/or Confidential Information and is intended solely for the use of the individual(s) to whom it is addressed. Any unauthorized review, use, disclosure, distribute, copy, or print is prohibited. If you are not an intended recipient, please contact the sender by reply email and destroy all copies of the original message. Thank you.

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

* Re: [EXT] [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC
  2022-02-10  5:54     ` Li Chen
@ 2022-02-10  7:47       ` Greg Kroah-Hartman
  0 siblings, 0 replies; 21+ messages in thread
From: Greg Kroah-Hartman @ 2022-02-10  7:47 UTC (permalink / raw)
  To: Li Chen
  Cc: Lad, Prabhakar, Lad Prabhakar, Kishon Vijay Abraham I,
	Bjorn Helgaas, Lorenzo Pieralisi, Krzysztof Wilczyński,
	Arnd Bergmann, Marek Vasut, Yoshihiro Shimoda, Rob Herring,
	linux-pci, linux-renesas-soc, linux-kernel, Biju Das

On Thu, Feb 10, 2022 at 05:54:26AM +0000, Li Chen wrote:
> **********************************************************************
> This email and attachments contain Ambarella Proprietary and/or Confidential Information and is intended solely for the use of the individual(s) to whom it is addressed. Any unauthorized review, use, disclosure, distribute, copy, or print is prohibited. If you are not an intended recipient, please contact the sender by reply email and destroy all copies of the original message. Thank you.

This email footer is not compatible with Linux kernel development,
sorry.  Please get your company to remove it so that you can continue to
participate.

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

* Re: [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC
  2022-01-26 19:50 [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC Lad Prabhakar
                   ` (5 preceding siblings ...)
  2022-02-09  4:47 ` [EXT] [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC Li Chen
@ 2022-02-10  8:40 ` Manivannan Sadhasivam
  2022-02-10  9:24   ` Lad, Prabhakar
  6 siblings, 1 reply; 21+ messages in thread
From: Manivannan Sadhasivam @ 2022-02-10  8:40 UTC (permalink / raw)
  To: Lad Prabhakar
  Cc: Kishon Vijay Abraham I, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Arnd Bergmann, Greg Kroah-Hartman,
	Marek Vasut, Yoshihiro Shimoda, Rob Herring, linux-pci,
	linux-renesas-soc, linux-kernel, Prabhakar, Biju Das

Hi,

On Wed, Jan 26, 2022 at 07:50:38PM +0000, Lad Prabhakar wrote:
> Hi All,
> 
> The current PCIe EPF framework supports DMA data transfers using external
> DMA only, this patch series aims to add support for platforms supporting
> internal DMAC on PCIe for data transfers.
> 
> R-Car PCIe supports internal DMAC to transfer data between Internal Bus to
> PCI Express and vice versa. Last patch fills up the required flags and ops
> to support internal DMAC.
> 
> Patches 1-3 are for PCIe EPF core to support internal DMAC handling, patch
> 4/5 is to fix test cases based on the conversation [1].
> 

This looks similar to the Synopsys eDMA IP [1] that goes with the Synopsys PCIe
endpoint IP. Why can't you represent it as a dmaengine driver and use the
existing DMA support?

Thanks,
Mani

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/dma/dw-edma 

> Patches are based on top of [1] next branch.
> 
> [0] https://www.spinics.net/lists/linux-pci/msg92385.html
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git
> 
> Cheers,
> Prabhakar
> 
> Lad Prabhakar (5):
>   PCI: endpoint: Add ops and flag to support internal DMAC
>   PCI: endpoint: Add support to data transfer using internal dmac
>   misc: pci_endpoint_test: Add driver data for Renesas RZ/G2{EHMN}
>   misc: pci_endpoint_test: Add support to pass flags for buffer
>     allocation
>   PCI: rcar-ep: Add support for DMAC
> 
>  drivers/misc/pci_endpoint_test.c              |  56 ++++-
>  drivers/pci/controller/pcie-rcar-ep.c         | 227 ++++++++++++++++++
>  drivers/pci/controller/pcie-rcar.h            |  23 ++
>  drivers/pci/endpoint/functions/pci-epf-test.c | 184 ++++++++++----
>  drivers/pci/endpoint/pci-epf-core.c           |  32 +++
>  include/linux/pci-epc.h                       |   8 +
>  include/linux/pci-epf.h                       |   7 +
>  7 files changed, 483 insertions(+), 54 deletions(-)
> 
> -- 
> 2.25.1
> 

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

* Re: [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC
  2022-02-10  8:40 ` Manivannan Sadhasivam
@ 2022-02-10  9:24   ` Lad, Prabhakar
  2022-02-10 10:50     ` Manivannan Sadhasivam
  0 siblings, 1 reply; 21+ messages in thread
From: Lad, Prabhakar @ 2022-02-10  9:24 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Lad Prabhakar, Kishon Vijay Abraham I, Bjorn Helgaas,
	Lorenzo Pieralisi, Krzysztof Wilczyński, Arnd Bergmann,
	Greg Kroah-Hartman, Marek Vasut, Yoshihiro Shimoda, Rob Herring,
	linux-pci, Linux-Renesas, LKML, Biju Das

Hi,

On Thu, Feb 10, 2022 at 8:40 AM Manivannan Sadhasivam
<manivannan.sadhasivam@linaro.org> wrote:
>
> Hi,
>
> On Wed, Jan 26, 2022 at 07:50:38PM +0000, Lad Prabhakar wrote:
> > Hi All,
> >
> > The current PCIe EPF framework supports DMA data transfers using external
> > DMA only, this patch series aims to add support for platforms supporting
> > internal DMAC on PCIe for data transfers.
> >
> > R-Car PCIe supports internal DMAC to transfer data between Internal Bus to
> > PCI Express and vice versa. Last patch fills up the required flags and ops
> > to support internal DMAC.
> >
> > Patches 1-3 are for PCIe EPF core to support internal DMAC handling, patch
> > 4/5 is to fix test cases based on the conversation [1].
> >
>
> This looks similar to the Synopsys eDMA IP [1] that goes with the Synopsys PCIe
> endpoint IP. Why can't you represent it as a dmaengine driver and use the
> existing DMA support?
>
Let me have a look. Could you please share a link to the Synopsys PCIe
endpoint HW manual (the driver doesn't have a binding doc).

Cheers,
Prabhakar

> [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/dma/dw-edma
>
> > Patches are based on top of [1] next branch.
> >
> > [0] https://www.spinics.net/lists/linux-pci/msg92385.html
> > [1] https://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git
> >
> > Cheers,
> > Prabhakar
> >
> > Lad Prabhakar (5):
> >   PCI: endpoint: Add ops and flag to support internal DMAC
> >   PCI: endpoint: Add support to data transfer using internal dmac
> >   misc: pci_endpoint_test: Add driver data for Renesas RZ/G2{EHMN}
> >   misc: pci_endpoint_test: Add support to pass flags for buffer
> >     allocation
> >   PCI: rcar-ep: Add support for DMAC
> >
> >  drivers/misc/pci_endpoint_test.c              |  56 ++++-
> >  drivers/pci/controller/pcie-rcar-ep.c         | 227 ++++++++++++++++++
> >  drivers/pci/controller/pcie-rcar.h            |  23 ++
> >  drivers/pci/endpoint/functions/pci-epf-test.c | 184 ++++++++++----
> >  drivers/pci/endpoint/pci-epf-core.c           |  32 +++
> >  include/linux/pci-epc.h                       |   8 +
> >  include/linux/pci-epf.h                       |   7 +
> >  7 files changed, 483 insertions(+), 54 deletions(-)
> >
> > --
> > 2.25.1
> >

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

* Re: [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC
  2022-02-10  9:24   ` Lad, Prabhakar
@ 2022-02-10 10:50     ` Manivannan Sadhasivam
  2022-02-10 11:05       ` Lad, Prabhakar
  0 siblings, 1 reply; 21+ messages in thread
From: Manivannan Sadhasivam @ 2022-02-10 10:50 UTC (permalink / raw)
  To: Lad, Prabhakar
  Cc: Lad Prabhakar, Kishon Vijay Abraham I, Bjorn Helgaas,
	Lorenzo Pieralisi, Krzysztof Wilczyński, Arnd Bergmann,
	Greg Kroah-Hartman, Marek Vasut, Yoshihiro Shimoda, Rob Herring,
	linux-pci, Linux-Renesas, LKML, Biju Das

On Thu, Feb 10, 2022 at 09:24:19AM +0000, Lad, Prabhakar wrote:
> Hi,
> 
> On Thu, Feb 10, 2022 at 8:40 AM Manivannan Sadhasivam
> <manivannan.sadhasivam@linaro.org> wrote:
> >
> > Hi,
> >
> > On Wed, Jan 26, 2022 at 07:50:38PM +0000, Lad Prabhakar wrote:
> > > Hi All,
> > >
> > > The current PCIe EPF framework supports DMA data transfers using external
> > > DMA only, this patch series aims to add support for platforms supporting
> > > internal DMAC on PCIe for data transfers.
> > >
> > > R-Car PCIe supports internal DMAC to transfer data between Internal Bus to
> > > PCI Express and vice versa. Last patch fills up the required flags and ops
> > > to support internal DMAC.
> > >
> > > Patches 1-3 are for PCIe EPF core to support internal DMAC handling, patch
> > > 4/5 is to fix test cases based on the conversation [1].
> > >
> >
> > This looks similar to the Synopsys eDMA IP [1] that goes with the Synopsys PCIe
> > endpoint IP. Why can't you represent it as a dmaengine driver and use the
> > existing DMA support?
> >
> Let me have a look. Could you please share a link to the Synopsys PCIe
> endpoint HW manual (the driver doesn't have a binding doc).
> 

I don't think the PCIe reference manual is available publicly. And you are right
that the driver is not tied to devicetree. The reason is, it gets probed using
the PCI ID of the EP and all the resources are defined statically in the driver
itself.

Thanks,
Mani

> Cheers,
> Prabhakar
> 
> > [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/dma/dw-edma
> >
> > > Patches are based on top of [1] next branch.
> > >
> > > [0] https://www.spinics.net/lists/linux-pci/msg92385.html
> > > [1] https://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git
> > >
> > > Cheers,
> > > Prabhakar
> > >
> > > Lad Prabhakar (5):
> > >   PCI: endpoint: Add ops and flag to support internal DMAC
> > >   PCI: endpoint: Add support to data transfer using internal dmac
> > >   misc: pci_endpoint_test: Add driver data for Renesas RZ/G2{EHMN}
> > >   misc: pci_endpoint_test: Add support to pass flags for buffer
> > >     allocation
> > >   PCI: rcar-ep: Add support for DMAC
> > >
> > >  drivers/misc/pci_endpoint_test.c              |  56 ++++-
> > >  drivers/pci/controller/pcie-rcar-ep.c         | 227 ++++++++++++++++++
> > >  drivers/pci/controller/pcie-rcar.h            |  23 ++
> > >  drivers/pci/endpoint/functions/pci-epf-test.c | 184 ++++++++++----
> > >  drivers/pci/endpoint/pci-epf-core.c           |  32 +++
> > >  include/linux/pci-epc.h                       |   8 +
> > >  include/linux/pci-epf.h                       |   7 +
> > >  7 files changed, 483 insertions(+), 54 deletions(-)
> > >
> > > --
> > > 2.25.1
> > >

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

* Re: [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC
  2022-02-10 10:50     ` Manivannan Sadhasivam
@ 2022-02-10 11:05       ` Lad, Prabhakar
  2022-02-10 13:22         ` Manivannan Sadhasivam
  0 siblings, 1 reply; 21+ messages in thread
From: Lad, Prabhakar @ 2022-02-10 11:05 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Lad Prabhakar, Kishon Vijay Abraham I, Bjorn Helgaas,
	Lorenzo Pieralisi, Krzysztof Wilczyński, Arnd Bergmann,
	Greg Kroah-Hartman, Marek Vasut, Yoshihiro Shimoda, Rob Herring,
	linux-pci, Linux-Renesas, LKML, Biju Das

On Thu, Feb 10, 2022 at 10:50 AM Manivannan Sadhasivam
<manivannan.sadhasivam@linaro.org> wrote:
>
> On Thu, Feb 10, 2022 at 09:24:19AM +0000, Lad, Prabhakar wrote:
> > Hi,
> >
> > On Thu, Feb 10, 2022 at 8:40 AM Manivannan Sadhasivam
> > <manivannan.sadhasivam@linaro.org> wrote:
> > >
> > > Hi,
> > >
> > > On Wed, Jan 26, 2022 at 07:50:38PM +0000, Lad Prabhakar wrote:
> > > > Hi All,
> > > >
> > > > The current PCIe EPF framework supports DMA data transfers using external
> > > > DMA only, this patch series aims to add support for platforms supporting
> > > > internal DMAC on PCIe for data transfers.
> > > >
> > > > R-Car PCIe supports internal DMAC to transfer data between Internal Bus to
> > > > PCI Express and vice versa. Last patch fills up the required flags and ops
> > > > to support internal DMAC.
> > > >
> > > > Patches 1-3 are for PCIe EPF core to support internal DMAC handling, patch
> > > > 4/5 is to fix test cases based on the conversation [1].
> > > >
> > >
> > > This looks similar to the Synopsys eDMA IP [1] that goes with the Synopsys PCIe
> > > endpoint IP. Why can't you represent it as a dmaengine driver and use the
> > > existing DMA support?
> > >
> > Let me have a look. Could you please share a link to the Synopsys PCIe
> > endpoint HW manual (the driver doesn't have a binding doc).
> >
>
> I don't think the PCIe reference manual is available publicly. And you are right
> that the driver is not tied to devicetree. The reason is, it gets probed using
> the PCI ID of the EP and all the resources are defined statically in the driver
> itself.
>
In R-Car PCIe the internal dmac is part of the PCIe block itself [0]
and not a separate block. I don't see any drivers implementing the
internal dmac drivers as a DMA engine driver. For example the Renesas
SDHI driver has internal dmac too, this is handled in the SDHI driver
itself [1] and not implemented as DMA engine driver. Let me know if my
understanding is wrong here.

[0] https://elixir.bootlin.com/linux/v5.17-rc3/source/Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml#L76
[1] https://elixir.bootlin.com/linux/v5.17-rc3/source/drivers/mmc/host/renesas_sdhi_internal_dmac.c

Cheers,
Prabhakar

> Thanks,
> Mani
>
> > Cheers,
> > Prabhakar
> >
> > > [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/dma/dw-edma
> > >
> > > > Patches are based on top of [1] next branch.
> > > >
> > > > [0] https://www.spinics.net/lists/linux-pci/msg92385.html
> > > > [1] https://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git
> > > >
> > > > Cheers,
> > > > Prabhakar
> > > >
> > > > Lad Prabhakar (5):
> > > >   PCI: endpoint: Add ops and flag to support internal DMAC
> > > >   PCI: endpoint: Add support to data transfer using internal dmac
> > > >   misc: pci_endpoint_test: Add driver data for Renesas RZ/G2{EHMN}
> > > >   misc: pci_endpoint_test: Add support to pass flags for buffer
> > > >     allocation
> > > >   PCI: rcar-ep: Add support for DMAC
> > > >
> > > >  drivers/misc/pci_endpoint_test.c              |  56 ++++-
> > > >  drivers/pci/controller/pcie-rcar-ep.c         | 227 ++++++++++++++++++
> > > >  drivers/pci/controller/pcie-rcar.h            |  23 ++
> > > >  drivers/pci/endpoint/functions/pci-epf-test.c | 184 ++++++++++----
> > > >  drivers/pci/endpoint/pci-epf-core.c           |  32 +++
> > > >  include/linux/pci-epc.h                       |   8 +
> > > >  include/linux/pci-epf.h                       |   7 +
> > > >  7 files changed, 483 insertions(+), 54 deletions(-)
> > > >
> > > > --
> > > > 2.25.1
> > > >

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

* Re: [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC
  2022-02-10 11:05       ` Lad, Prabhakar
@ 2022-02-10 13:22         ` Manivannan Sadhasivam
  0 siblings, 0 replies; 21+ messages in thread
From: Manivannan Sadhasivam @ 2022-02-10 13:22 UTC (permalink / raw)
  To: Lad, Prabhakar
  Cc: Lad Prabhakar, Kishon Vijay Abraham I, Bjorn Helgaas,
	Lorenzo Pieralisi, Krzysztof Wilczyński, Arnd Bergmann,
	Greg Kroah-Hartman, Marek Vasut, Yoshihiro Shimoda, Rob Herring,
	linux-pci, Linux-Renesas, LKML, Biju Das

On Thu, Feb 10, 2022 at 11:05:45AM +0000, Lad, Prabhakar wrote:
> On Thu, Feb 10, 2022 at 10:50 AM Manivannan Sadhasivam
> <manivannan.sadhasivam@linaro.org> wrote:
> >
> > On Thu, Feb 10, 2022 at 09:24:19AM +0000, Lad, Prabhakar wrote:
> > > Hi,
> > >
> > > On Thu, Feb 10, 2022 at 8:40 AM Manivannan Sadhasivam
> > > <manivannan.sadhasivam@linaro.org> wrote:
> > > >
> > > > Hi,
> > > >
> > > > On Wed, Jan 26, 2022 at 07:50:38PM +0000, Lad Prabhakar wrote:
> > > > > Hi All,
> > > > >
> > > > > The current PCIe EPF framework supports DMA data transfers using external
> > > > > DMA only, this patch series aims to add support for platforms supporting
> > > > > internal DMAC on PCIe for data transfers.
> > > > >
> > > > > R-Car PCIe supports internal DMAC to transfer data between Internal Bus to
> > > > > PCI Express and vice versa. Last patch fills up the required flags and ops
> > > > > to support internal DMAC.
> > > > >
> > > > > Patches 1-3 are for PCIe EPF core to support internal DMAC handling, patch
> > > > > 4/5 is to fix test cases based on the conversation [1].
> > > > >
> > > >
> > > > This looks similar to the Synopsys eDMA IP [1] that goes with the Synopsys PCIe
> > > > endpoint IP. Why can't you represent it as a dmaengine driver and use the
> > > > existing DMA support?
> > > >
> > > Let me have a look. Could you please share a link to the Synopsys PCIe
> > > endpoint HW manual (the driver doesn't have a binding doc).
> > >
> >
> > I don't think the PCIe reference manual is available publicly. And you are right
> > that the driver is not tied to devicetree. The reason is, it gets probed using
> > the PCI ID of the EP and all the resources are defined statically in the driver
> > itself.
> >
> In R-Car PCIe the internal dmac is part of the PCIe block itself [0]
> and not a separate block. I don't see any drivers implementing the
> internal dmac drivers as a DMA engine driver. For example the Renesas
> SDHI driver has internal dmac too, this is handled in the SDHI driver
> itself [1] and not implemented as DMA engine driver. Let me know if my
> understanding is wrong here.
> 

Okay, thanks for the clarification. I thought that if the IP is same, we could
implement it as a standalone DMA engine driver, but looks like it is customized.
So I guess it is reasonable to have an internal implementation.

Thanks,
Mani

> [0] https://elixir.bootlin.com/linux/v5.17-rc3/source/Documentation/devicetree/bindings/pci/rcar-pci-ep.yaml#L76
> [1] https://elixir.bootlin.com/linux/v5.17-rc3/source/drivers/mmc/host/renesas_sdhi_internal_dmac.c
> 
> Cheers,
> Prabhakar
> 
> > Thanks,
> > Mani
> >
> > > Cheers,
> > > Prabhakar
> > >
> > > > [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/dma/dw-edma
> > > >
> > > > > Patches are based on top of [1] next branch.
> > > > >
> > > > > [0] https://www.spinics.net/lists/linux-pci/msg92385.html
> > > > > [1] https://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci.git
> > > > >
> > > > > Cheers,
> > > > > Prabhakar
> > > > >
> > > > > Lad Prabhakar (5):
> > > > >   PCI: endpoint: Add ops and flag to support internal DMAC
> > > > >   PCI: endpoint: Add support to data transfer using internal dmac
> > > > >   misc: pci_endpoint_test: Add driver data for Renesas RZ/G2{EHMN}
> > > > >   misc: pci_endpoint_test: Add support to pass flags for buffer
> > > > >     allocation
> > > > >   PCI: rcar-ep: Add support for DMAC
> > > > >
> > > > >  drivers/misc/pci_endpoint_test.c              |  56 ++++-
> > > > >  drivers/pci/controller/pcie-rcar-ep.c         | 227 ++++++++++++++++++
> > > > >  drivers/pci/controller/pcie-rcar.h            |  23 ++
> > > > >  drivers/pci/endpoint/functions/pci-epf-test.c | 184 ++++++++++----
> > > > >  drivers/pci/endpoint/pci-epf-core.c           |  32 +++
> > > > >  include/linux/pci-epc.h                       |   8 +
> > > > >  include/linux/pci-epf.h                       |   7 +
> > > > >  7 files changed, 483 insertions(+), 54 deletions(-)
> > > > >
> > > > > --
> > > > > 2.25.1
> > > > >

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

* Re: [RFC PATCH 1/5] PCI: endpoint: Add ops and flag to support internal DMAC
  2022-01-26 19:50 ` [RFC PATCH 1/5] PCI: endpoint: Add ops and flag to support internal DMAC Lad Prabhakar
@ 2022-02-14  9:30   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 21+ messages in thread
From: Manivannan Sadhasivam @ 2022-02-14  9:30 UTC (permalink / raw)
  To: Lad Prabhakar
  Cc: Kishon Vijay Abraham I, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Arnd Bergmann, Greg Kroah-Hartman,
	Marek Vasut, Yoshihiro Shimoda, Rob Herring, linux-pci,
	linux-renesas-soc, linux-kernel, Prabhakar, Biju Das

On Wed, Jan 26, 2022 at 07:50:39PM +0000, Lad Prabhakar wrote:
> Add flag to indicate if PCIe EP supports internal DMAC and also add a
> wrapper function which invokes dmac_transfer() callback which lands
> in the PCIe EP driver.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> ---
>  drivers/pci/endpoint/pci-epf-core.c | 32 +++++++++++++++++++++++++++++
>  include/linux/pci-epc.h             |  8 ++++++++
>  include/linux/pci-epf.h             |  7 +++++++
>  3 files changed, 47 insertions(+)
> 
> diff --git a/drivers/pci/endpoint/pci-epf-core.c b/drivers/pci/endpoint/pci-epf-core.c
> index 9ed556936f48..f70576d0d4b2 100644
> --- a/drivers/pci/endpoint/pci-epf-core.c
> +++ b/drivers/pci/endpoint/pci-epf-core.c
> @@ -239,6 +239,38 @@ void pci_epf_remove_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf)
>  }
>  EXPORT_SYMBOL_GPL(pci_epf_remove_vepf);
>  
> +/**
> + * pci_epf_internal_dmac_xfr() - transfer data between EPC and remote PCIe RC

Transfer data between EP and host using internal DMA engine

> + * @epf: the EPF device that performs the data transfer operation
> + * @dma_dst: The destination address of the data transfer. It can be a physical
> + *	     address given by pci_epc_mem_alloc_addr or DMA mapping APIs.
> + * @dma_src: The source address of the data transfer. It can be a physical
> + *	     address given by pci_epc_mem_alloc_addr or DMA mapping APIs.
> + * @len: The size of the data transfer
> + *
> + * Invoke to transfer data between EPC and remote PCIe RC using internal dmac.
> + */
> +int pci_epf_internal_dmac_xfr(struct pci_epf *epf, dma_addr_t dma_dst,
> +			      dma_addr_t dma_src, size_t len,
> +			      enum pci_epf_xfr_direction dir)

How about "pci_epf_internal_dma_xfer"? I think DMAC is somewhat platform
specific so we could just use DMA. And "xfer" is being used more commonly for
"transfer".

> +{
> +	struct pci_epc *epc = epf->epc;
> +	int ret;
> +
> +	if (IS_ERR_OR_NULL(epc) || IS_ERR_OR_NULL(epf))
> +		return -EINVAL;
> +
> +	if (!epc->ops->dmac_transfer)
> +		return -EINVAL;
> +
> +	mutex_lock(&epf->lock);
> +	ret = epc->ops->dmac_transfer(epc, epf, dma_dst, dma_src, len, dir);

internal_dma_xfer? It doesn't look perfect but I can't think of any other way to
represent it as an internal dma callback.

> +	mutex_unlock(&epf->lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(pci_epf_internal_dmac_xfr);
> +
>  /**
>   * pci_epf_free_space() - free the allocated PCI EPF register space
>   * @epf: the EPF device from whom to free the memory
> diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
> index a48778e1a4ee..b55dacd09e1e 100644
> --- a/include/linux/pci-epc.h
> +++ b/include/linux/pci-epc.h
> @@ -58,6 +58,7 @@ pci_epc_interface_string(enum pci_epc_interface_type type)
>   * @map_msi_irq: ops to map physical address to MSI address and return MSI data
>   * @start: ops to start the PCI link
>   * @stop: ops to stop the PCI link
> + * @dmac_transfer: ops to transfer data using internal DMAC
>   * @get_features: ops to get the features supported by the EPC
>   * @owner: the module owner containing the ops
>   */
> @@ -86,6 +87,9 @@ struct pci_epc_ops {
>  			       u32 *msi_addr_offset);
>  	int	(*start)(struct pci_epc *epc);
>  	void	(*stop)(struct pci_epc *epc);
> +	int	(*dmac_transfer)(struct pci_epc *epc, struct pci_epf *epf,
> +				 dma_addr_t dma_dst, dma_addr_t dma_src,
> +				 size_t len, enum pci_epf_xfr_direction dir);
>  	const struct pci_epc_features* (*get_features)(struct pci_epc *epc,
>  						       u8 func_no, u8 vfunc_no);
>  	struct module *owner;
> @@ -159,6 +163,8 @@ struct pci_epc {
>   *			for initialization
>   * @msi_capable: indicate if the endpoint function has MSI capability
>   * @msix_capable: indicate if the endpoint function has MSI-X capability
> + * @internal_dmac: indicate if the endpoint function has internal DMAC
> + * @internal_dmac_mask: indicates the DMA mask to be applied for the device
>   * @reserved_bar: bitmap to indicate reserved BAR unavailable to function driver
>   * @bar_fixed_64bit: bitmap to indicate fixed 64bit BARs
>   * @bar_fixed_size: Array specifying the size supported by each BAR
> @@ -169,6 +175,8 @@ struct pci_epc_features {
>  	unsigned int	core_init_notifier : 1;
>  	unsigned int	msi_capable : 1;
>  	unsigned int	msix_capable : 1;
> +	unsigned int	internal_dmac : 1;
> +	u64		internal_dmac_mask;

internal_dma?

>  	u8	reserved_bar;
>  	u8	bar_fixed_64bit;
>  	u64	bar_fixed_size[PCI_STD_NUM_BARS];
> diff --git a/include/linux/pci-epf.h b/include/linux/pci-epf.h
> index 009a07147c61..78d661db085d 100644
> --- a/include/linux/pci-epf.h
> +++ b/include/linux/pci-epf.h
> @@ -32,6 +32,11 @@ enum pci_barno {
>  	BAR_5,
>  };
>  
> +enum pci_epf_xfr_direction {
> +	PCIE_TO_INTERNAL,
> +	INTERNAL_TO_PCIE,

I think we could just use "dma_data_direction" as we are anyway transferring
data between host and device.

Thanks,
Mani

> +};
> +
>  /**
>   * struct pci_epf_header - represents standard configuration header
>   * @vendorid: identifies device manufacturer
> @@ -209,6 +214,8 @@ void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar,
>  			enum pci_epc_interface_type type);
>  int pci_epf_bind(struct pci_epf *epf);
>  void pci_epf_unbind(struct pci_epf *epf);
> +int pci_epf_internal_dmac_xfr(struct pci_epf *epf, dma_addr_t dma_dst, dma_addr_t dma_src,
> +			      size_t len, enum pci_epf_xfr_direction dir);
>  struct config_group *pci_epf_type_add_cfs(struct pci_epf *epf,
>  					  struct config_group *group);
>  int pci_epf_add_vepf(struct pci_epf *epf_pf, struct pci_epf *epf_vf);
> -- 
> 2.25.1
> 

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

* Re: [RFC PATCH 2/5] PCI: endpoint: Add support to data transfer using internal dmac
  2022-01-26 19:50 ` [RFC PATCH 2/5] PCI: endpoint: Add support to data transfer using internal dmac Lad Prabhakar
@ 2022-02-14  9:49   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 21+ messages in thread
From: Manivannan Sadhasivam @ 2022-02-14  9:49 UTC (permalink / raw)
  To: Lad Prabhakar
  Cc: Kishon Vijay Abraham I, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Arnd Bergmann, Greg Kroah-Hartman,
	Marek Vasut, Yoshihiro Shimoda, Rob Herring, linux-pci,
	linux-renesas-soc, linux-kernel, Prabhakar, Biju Das

On Wed, Jan 26, 2022 at 07:50:40PM +0000, Lad Prabhakar wrote:
> For PCIe EP capable with internal DMAC, transfer data using this
> when -d option is used with pcitest.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> ---
>  drivers/pci/endpoint/functions/pci-epf-test.c | 184 ++++++++++++++----
>  1 file changed, 141 insertions(+), 43 deletions(-)
> 
> diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
> index 90d84d3bc868..f792b1a15c44 100644
> --- a/drivers/pci/endpoint/functions/pci-epf-test.c
> +++ b/drivers/pci/endpoint/functions/pci-epf-test.c
> @@ -55,6 +55,7 @@ struct pci_epf_test {
>  	struct dma_chan		*dma_chan;
>  	struct completion	transfer_complete;
>  	bool			dma_supported;
> +	bool			internal_dmac;

Please use "dma" everywhere.

>  	const struct pci_epc_features *epc_features;
>  };
>  
> @@ -148,6 +149,40 @@ static int pci_epf_test_data_transfer(struct pci_epf_test *epf_test,
>  	return 0;
>  }
>  
> +/**
> + * pci_epf_test_internal_dmac_data_transfer() - Function that uses internal DMAC
> + *				to transfer data between PCIe EP and remote PCIe RC
> + * @epf_test: the EPF test device that performs the data transfer operation
> + * @dma_dst: The destination address of the data transfer. It can be a physical
> + *	     address given by pci_epc_mem_alloc_addr or DMA mapping APIs.
> + * @dma_src: The source address of the data transfer. It can be a physical
> + *	     address given by pci_epc_mem_alloc_addr or DMA mapping APIs.
> + * @len: The size of the data transfer
> + * @dir: Direction of data transfer
> + *
> + * Function that uses internal dmac supported by the controller to transfer data
> + * between PCIe EP and remote PCIe RC.
> + *
> + * The function returns '0' on success and negative value on failure.
> + */
> +static int
> +pci_epf_test_internal_dmac_data_transfer(struct pci_epf_test *epf_test,
> +					 dma_addr_t dma_dst, dma_addr_t dma_src,
> +					 size_t len, enum pci_epf_xfr_direction dir)
> +{
> +	struct pci_epf *epf = epf_test->epf;
> +	int ret;
> +
> +	if (!epf_test->internal_dmac)
> +		return -EINVAL;
> +
> +	ret = pci_epf_internal_dmac_xfr(epf, dma_dst, dma_src, len, dir);
> +	if (ret)
> +		return -EIO;

Why can't you return "ret"?

> +
> +	return 0;
> +}
> +
>  /**
>   * pci_epf_test_init_dma_chan() - Function to initialize EPF test DMA channel
>   * @epf_test: the EPF test device that performs data transfer operation
> @@ -238,6 +273,14 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
>  	struct pci_epc *epc = epf->epc;
>  	enum pci_barno test_reg_bar = epf_test->test_reg_bar;
>  	struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
> +	bool internal_dmac = epf_test->internal_dmac;
> +
> +	use_dma = !!(reg->flags & FLAG_USE_DMA);
> +
> +	if (use_dma && internal_dmac) {
> +		dev_err(dev, "Operation not supported\n");

Here you are erroring out but below you are checking for this condition to do
internal DMA transfer.

> +		return -EINVAL;
> +	}
>  
>  	src_addr = pci_epc_mem_alloc_addr(epc, &src_phys_addr, reg->size);
>  	if (!src_addr) {
> @@ -272,7 +315,6 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)

Why internal DMA is not used in pci_epf_test_copy()?

>  	}
>  
>  	ktime_get_ts64(&start);
> -	use_dma = !!(reg->flags & FLAG_USE_DMA);
>  	if (use_dma) {
>  		if (!epf_test->dma_supported) {
>  			dev_err(dev, "Cannot transfer data using DMA\n");
> @@ -322,31 +364,49 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
>  	struct device *dma_dev = epf->epc->dev.parent;
>  	enum pci_barno test_reg_bar = epf_test->test_reg_bar;
>  	struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
> +	bool internal_dmac = epf_test->internal_dmac;
>  
> -	src_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
> -	if (!src_addr) {
> -		dev_err(dev, "Failed to allocate address\n");
> -		reg->status = STATUS_SRC_ADDR_INVALID;
> -		ret = -ENOMEM;
> -		goto err;
> -	}
> +	use_dma = !!(reg->flags & FLAG_USE_DMA);
>  
> -	ret = pci_epc_map_addr(epc, epf->func_no, epf->vfunc_no, phys_addr,
> -			       reg->src_addr, reg->size);
> -	if (ret) {
> -		dev_err(dev, "Failed to map address\n");
> -		reg->status = STATUS_SRC_ADDR_INVALID;
> -		goto err_addr;
> +	if (use_dma && internal_dmac) {

Both are mutually exclusive, isn't it?

> +		phys_addr = reg->src_addr;
> +		src_addr = NULL;
> +	} else {
> +		src_addr = pci_epc_mem_alloc_addr(epc, &phys_addr, reg->size);
> +		if (!src_addr) {
> +			dev_err(dev, "Failed to allocate address\n");
> +			reg->status = STATUS_SRC_ADDR_INVALID;
> +			ret = -ENOMEM;
> +			goto err;
> +		}
> +
> +		ret = pci_epc_map_addr(epc, epf->func_no, epf->vfunc_no, phys_addr,
> +				       reg->src_addr, reg->size);
> +		if (ret) {
> +			dev_err(dev, "Failed to map address\n");
> +			reg->status = STATUS_SRC_ADDR_INVALID;
> +			goto err_addr;
> +		}
>  	}
>  

[...]

>  
>  	ret = pci_epf_test_alloc_space(epf);
>  	if (ret)
> @@ -868,11 +964,13 @@ static int pci_epf_test_bind(struct pci_epf *epf)
>  			return ret;
>  	}
>  
> -	epf_test->dma_supported = true;
> +	epf_test->dma_supported = false;
>  
> -	ret = pci_epf_test_init_dma_chan(epf_test);
> -	if (ret)
> -		epf_test->dma_supported = false;
> +	if (!epf_test->internal_dmac) {
> +		ret = pci_epf_test_init_dma_chan(epf_test);
> +		if (!ret)
> +			epf_test->dma_supported = true;

You can set this flag to true inside pci_epf_test_init_dma_chan().

Thanks,
Mani

> +	}
>  
>  	if (linkup_notifier) {
>  		epf->nb.notifier_call = pci_epf_test_notifier;
> -- 
> 2.25.1
> 

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

* Re: [RFC PATCH 3/5] misc: pci_endpoint_test: Add driver data for Renesas RZ/G2{EHMN}
  2022-01-26 19:50 ` [RFC PATCH 3/5] misc: pci_endpoint_test: Add driver data for Renesas RZ/G2{EHMN} Lad Prabhakar
@ 2022-02-14 10:02   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 21+ messages in thread
From: Manivannan Sadhasivam @ 2022-02-14 10:02 UTC (permalink / raw)
  To: Lad Prabhakar
  Cc: Kishon Vijay Abraham I, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Arnd Bergmann, Greg Kroah-Hartman,
	Marek Vasut, Yoshihiro Shimoda, Rob Herring, linux-pci,
	linux-renesas-soc, linux-kernel, Prabhakar, Biju Das

On Wed, Jan 26, 2022 at 07:50:41PM +0000, Lad Prabhakar wrote:
> Add "dmac_data_alignment" member (indicating the alignment requirement
> for internal DMAC for data transfers) to struct pci_endpoint_test_data
> and add driver_data to Renesas RZ/G2{EHMN}.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> ---
>  drivers/misc/pci_endpoint_test.c | 40 ++++++++++++++++++++++++++------
>  1 file changed, 33 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
> index 8f786a225dcf..0a00d45830e9 100644
> --- a/drivers/misc/pci_endpoint_test.c
> +++ b/drivers/misc/pci_endpoint_test.c
> @@ -116,6 +116,7 @@ struct pci_endpoint_test {
>  	struct miscdevice miscdev;
>  	enum pci_barno test_reg_bar;
>  	size_t alignment;
> +	size_t dmac_data_alignment;

Alignment is a generic requirement, so this could be "dma_alignment" or
"data_alignment". Eventhough the only current user is internal DMA, this can
also be used by others in the future.

Thanks,
Mani

>  	const char *name;
>  };
>  
> @@ -123,6 +124,7 @@ struct pci_endpoint_test_data {
>  	enum pci_barno test_reg_bar;
>  	size_t alignment;
>  	int irq_type;
> +	size_t dmac_data_alignment;
>  };
>  
>  static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test,
> @@ -368,8 +370,11 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
>  		goto err;
>  
>  	use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
> -	if (use_dma)
> +	if (use_dma) {
>  		flags |= FLAG_USE_DMA;
> +		if (test->dmac_data_alignment)
> +			size =  ALIGN(size, test->dmac_data_alignment);
> +	}
>  
>  	if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
>  		dev_err(dev, "Invalid IRQ type option\n");
> @@ -502,8 +507,11 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
>  		goto err;
>  
>  	use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
> -	if (use_dma)
> +	if (use_dma) {
>  		flags |= FLAG_USE_DMA;
> +		if (test->dmac_data_alignment)
> +			size =  ALIGN(size, test->dmac_data_alignment);
> +	}
>  
>  	if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
>  		dev_err(dev, "Invalid IRQ type option\n");
> @@ -600,8 +608,11 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
>  		goto err;
>  
>  	use_dma = !!(param.flags & PCITEST_FLAGS_USE_DMA);
> -	if (use_dma)
> +	if (use_dma) {
>  		flags |= FLAG_USE_DMA;
> +		if (test->dmac_data_alignment)
> +			size =  ALIGN(size, test->dmac_data_alignment);
> +	}
>  
>  	if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
>  		dev_err(dev, "Invalid IRQ type option\n");
> @@ -787,6 +798,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
>  		test->test_reg_bar = test_reg_bar;
>  		test->alignment = data->alignment;
>  		irq_type = data->irq_type;
> +		test->dmac_data_alignment = data->dmac_data_alignment;
>  	}
>  
>  	init_completion(&test->irq_raised);
> @@ -948,6 +960,12 @@ static const struct pci_endpoint_test_data j721e_data = {
>  	.irq_type = IRQ_TYPE_MSI,
>  };
>  
> +static const struct pci_endpoint_test_data renesas_rzg2x_data = {
> +	.test_reg_bar = BAR_0,
> +	.irq_type = IRQ_TYPE_MSI,
> +	.dmac_data_alignment = 8,
> +};
> +
>  static const struct pci_device_id pci_endpoint_test_tbl[] = {
>  	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_DRA74x),
>  	  .driver_data = (kernel_ulong_t)&default_data,
> @@ -965,10 +983,18 @@ static const struct pci_device_id pci_endpoint_test_tbl[] = {
>  	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_AM654),
>  	  .driver_data = (kernel_ulong_t)&am654_data
>  	},
> -	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774A1),},
> -	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774B1),},
> -	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774C0),},
> -	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774E1),},
> +	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774A1),
> +	 .driver_data = (kernel_ulong_t)&renesas_rzg2x_data,
> +	},
> +	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774B1),
> +	 .driver_data = (kernel_ulong_t)&renesas_rzg2x_data,
> +	},
> +	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774C0),
> +	 .driver_data = (kernel_ulong_t)&renesas_rzg2x_data,
> +	},
> +	{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, PCI_DEVICE_ID_RENESAS_R8A774E1),
> +	 .driver_data = (kernel_ulong_t)&renesas_rzg2x_data,
> +	},
>  	{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_J721E),
>  	  .driver_data = (kernel_ulong_t)&j721e_data,
>  	},
> -- 
> 2.25.1
> 

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

* Re: [RFC PATCH 4/5] misc: pci_endpoint_test: Add support to pass flags for buffer allocation
  2022-01-26 19:50 ` [RFC PATCH 4/5] misc: pci_endpoint_test: Add support to pass flags for buffer allocation Lad Prabhakar
@ 2022-02-14 10:11   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 21+ messages in thread
From: Manivannan Sadhasivam @ 2022-02-14 10:11 UTC (permalink / raw)
  To: Lad Prabhakar
  Cc: Kishon Vijay Abraham I, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Arnd Bergmann, Greg Kroah-Hartman,
	Marek Vasut, Yoshihiro Shimoda, Rob Herring, linux-pci,
	linux-renesas-soc, linux-kernel, Prabhakar, Biju Das

On Wed, Jan 26, 2022 at 07:50:42PM +0000, Lad Prabhakar wrote:
> By default GFP_KERNEL flag is used for buffer allocation in read, write
> and copy test and then later mapped using streaming DMA api. But on
> Renesas RZ/G2{EHMN} platforms using the default flag causes the tests to
> fail. Allocating the buffers from DMA zone (using the GFP_DMA flag) make
> the test cases to pass.
> 
> To handle such case add flags as part of struct pci_endpoint_test_data
> so that platforms can pass the required flags based on the requirement.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> ---
> Hi All,
> 
> This patch is based on the conversation where switching to streaming
> DMA api causes read/write/copy tests to fail on Renesas RZ/G2 platforms
> when buffers are allocated using GFP_KERNEL.
> 
> [0] https://www.spinics.net/lists/linux-pci/msg92385.html
> 
> Cheers,
> Prabhakar
> ---
>  drivers/misc/pci_endpoint_test.c | 16 ++++++++++++----
>  1 file changed, 12 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
> index 0a00d45830e9..974546992c5e 100644
> --- a/drivers/misc/pci_endpoint_test.c
> +++ b/drivers/misc/pci_endpoint_test.c
> @@ -117,6 +117,7 @@ struct pci_endpoint_test {
>  	enum pci_barno test_reg_bar;
>  	size_t alignment;
>  	size_t dmac_data_alignment;
> +	gfp_t flags;

gfp_flags? Since this is used for allocation.

Thanks,
Mani

>  	const char *name;
>  };
>  
> @@ -125,6 +126,7 @@ struct pci_endpoint_test_data {
>  	size_t alignment;
>  	int irq_type;
>  	size_t dmac_data_alignment;
> +	gfp_t flags;
>  };
>  
>  static inline u32 pci_endpoint_test_readl(struct pci_endpoint_test *test,
> @@ -381,7 +383,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
>  		goto err;
>  	}
>  
> -	orig_src_addr = kzalloc(size + alignment, GFP_KERNEL);
> +	orig_src_addr = kzalloc(size + alignment, test->flags);
>  	if (!orig_src_addr) {
>  		dev_err(dev, "Failed to allocate source buffer\n");
>  		ret = false;
> @@ -414,7 +416,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
>  
>  	src_crc32 = crc32_le(~0, src_addr, size);
>  
> -	orig_dst_addr = kzalloc(size + alignment, GFP_KERNEL);
> +	orig_dst_addr = kzalloc(size + alignment, test->flags);
>  	if (!orig_dst_addr) {
>  		dev_err(dev, "Failed to allocate destination address\n");
>  		ret = false;
> @@ -518,7 +520,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
>  		goto err;
>  	}
>  
> -	orig_addr = kzalloc(size + alignment, GFP_KERNEL);
> +	orig_addr = kzalloc(size + alignment, test->flags);
>  	if (!orig_addr) {
>  		dev_err(dev, "Failed to allocate address\n");
>  		ret = false;
> @@ -619,7 +621,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
>  		goto err;
>  	}
>  
> -	orig_addr = kzalloc(size + alignment, GFP_KERNEL);
> +	orig_addr = kzalloc(size + alignment, test->flags);
>  	if (!orig_addr) {
>  		dev_err(dev, "Failed to allocate destination address\n");
>  		ret = false;
> @@ -788,6 +790,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
>  	test->alignment = 0;
>  	test->pdev = pdev;
>  	test->irq_type = IRQ_TYPE_UNDEFINED;
> +	test->flags = GFP_KERNEL;
>  
>  	if (no_msi)
>  		irq_type = IRQ_TYPE_LEGACY;
> @@ -799,6 +802,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
>  		test->alignment = data->alignment;
>  		irq_type = data->irq_type;
>  		test->dmac_data_alignment = data->dmac_data_alignment;
> +		test->flags = data->flags;
>  	}
>  
>  	init_completion(&test->irq_raised);
> @@ -947,23 +951,27 @@ static const struct pci_endpoint_test_data default_data = {
>  	.test_reg_bar = BAR_0,
>  	.alignment = SZ_4K,
>  	.irq_type = IRQ_TYPE_MSI,
> +	.flags = GFP_KERNEL,
>  };
>  
>  static const struct pci_endpoint_test_data am654_data = {
>  	.test_reg_bar = BAR_2,
>  	.alignment = SZ_64K,
>  	.irq_type = IRQ_TYPE_MSI,
> +	.flags = GFP_KERNEL,
>  };
>  
>  static const struct pci_endpoint_test_data j721e_data = {
>  	.alignment = 256,
>  	.irq_type = IRQ_TYPE_MSI,
> +	.flags = GFP_KERNEL,
>  };
>  
>  static const struct pci_endpoint_test_data renesas_rzg2x_data = {
>  	.test_reg_bar = BAR_0,
>  	.irq_type = IRQ_TYPE_MSI,
>  	.dmac_data_alignment = 8,
> +	.flags = GFP_KERNEL | GFP_DMA,
>  };
>  
>  static const struct pci_device_id pci_endpoint_test_tbl[] = {
> -- 
> 2.25.1
> 

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

* Re: [RFC PATCH 5/5] PCI: rcar-ep: Add support for DMAC
  2022-01-26 19:50 ` [RFC PATCH 5/5] PCI: rcar-ep: Add support for DMAC Lad Prabhakar
@ 2022-02-14 10:40   ` Manivannan Sadhasivam
  2022-02-21  4:32   ` [EXT] " Li Chen
  1 sibling, 0 replies; 21+ messages in thread
From: Manivannan Sadhasivam @ 2022-02-14 10:40 UTC (permalink / raw)
  To: Lad Prabhakar
  Cc: Kishon Vijay Abraham I, Bjorn Helgaas, Lorenzo Pieralisi,
	Krzysztof Wilczyński, Arnd Bergmann, Greg Kroah-Hartman,
	Marek Vasut, Yoshihiro Shimoda, Rob Herring, linux-pci,
	linux-renesas-soc, linux-kernel, Prabhakar, Biju Das

On Wed, Jan 26, 2022 at 07:50:43PM +0000, Lad Prabhakar wrote:
> R-Car PCIe controller has an internal DMAC to support data transfer
> between Internal Bus -> PCI Express and vice versa.
> 
> This patch fills in the required flags and ops for the PCIe EP to
> support DMAC transfer.
> 
> Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
> ---
>  drivers/pci/controller/pcie-rcar-ep.c | 227 ++++++++++++++++++++++++++
>  drivers/pci/controller/pcie-rcar.h    |  23 +++
>  2 files changed, 250 insertions(+)
> 
> diff --git a/drivers/pci/controller/pcie-rcar-ep.c b/drivers/pci/controller/pcie-rcar-ep.c
> index f9682df1da61..c49b25069328 100644
> --- a/drivers/pci/controller/pcie-rcar-ep.c
> +++ b/drivers/pci/controller/pcie-rcar-ep.c
> @@ -18,6 +18,21 @@
>  
>  #define RCAR_EPC_MAX_FUNCTIONS		1
>  
> +#define RCAR_PCIE_MAX_DMAC_BYTE_COUNT		0x7FFFFFFU
> +#define RCAR_PCIE_DMAC_BYTE_COUNT_MULTIPLE	8
> +#define RCAR_PCIE_DMAC_TIMEOUT			(msecs_to_jiffies(3 * 1000))
> +#define RCAR_PCIE_DMAC_DEFAULT_CHANNEL		0
> +
> +enum rcar_pcie_ep_dmac_xfr_status {
> +	RCAR_PCIE_DMA_XFR_SUCCESS,
> +	RCAR_PCIE_DMA_XFR_ERROR,
> +};
> +
> +struct rcar_pcie_ep_dmac_info {
> +	enum rcar_pcie_ep_dmac_xfr_status status;
> +	size_t bytes;
> +};
> +
>  /* Structure representing the PCIe interface */
>  struct rcar_pcie_endpoint {
>  	struct rcar_pcie	pcie;
> @@ -28,8 +43,114 @@ struct rcar_pcie_endpoint {
>  	unsigned long		*ib_window_map;
>  	u32			num_ib_windows;
>  	u32			num_ob_windows;
> +	struct completion	irq_raised;
> +	struct mutex		dma_operation;
> +	spinlock_t		lock;

Locks should be documented.

> +	struct rcar_pcie_ep_dmac_info xfr;
>  };
>  
> +static inline bool rcar_pcie_ep_is_dmac_active(struct rcar_pcie_endpoint *ep)

No need of "inline", compiler should be able to judge it.

> +{
> +	if (rcar_pci_read_reg(&ep->pcie, PCIEDMAOR) & PCIEDMAOR_DMAACT)
> +		return true;
> +
> +	return false;
> +}
> +
> +static void
> +rcar_pcie_ep_setup_dmac_request(struct rcar_pcie_endpoint *ep,
> +				dma_addr_t dma_dst, dma_addr_t dma_src,
> +				size_t len, enum pci_epf_xfr_direction dir, u8 ch)
> +{
> +	struct rcar_pcie *pcie = &ep->pcie;
> +	u32 val;
> +
> +	ep->xfr.status = RCAR_PCIE_DMA_XFR_ERROR;
> +	ep->xfr.bytes = RCAR_PCIE_MAX_DMAC_BYTE_COUNT;
> +
> +	/* swap values if xfr is from pcie to internal */
> +	if (dir == PCIE_TO_INTERNAL)
> +		swap(dma_dst, dma_src);
> +
> +	/* Configure the PCI Express lower */
> +	rcar_pci_write_reg(pcie, lower_32_bits(dma_dst), PCIEDMPALR(ch));
> +
> +	/* Configure the PCI Express upper */
> +	rcar_pci_write_reg(pcie, upper_32_bits(dma_dst), PCIEDMPAUR(ch));
> +
> +	/* Configure the internal bus address */
> +	rcar_pci_write_reg(pcie, lower_32_bits(dma_src), PCIEDMIAR(ch));
> +
> +	/* Configure the byte count values */
> +	rcar_pci_write_reg(pcie, len, PCIEDMBCNTR(ch));
> +
> +	/* Enable interrupts */
> +	val = rcar_pci_read_reg(pcie, PCIEDMCHSR(ch));
> +
> +	/* set enable flags */
> +	val |= PCIEDMCHSR_IE;
> +	val |= PCIEDMCHSR_IBEE;
> +	val |= PCIEDMCHSR_PEEE;
> +	val |= PCIEDMCHSR_CHTCE;
> +
> +	/* Clear error flags */
> +	val &= ~PCIEDMCHSR_TE;
> +	val &= ~PCIEDMCHSR_PEE;
> +	val &= ~PCIEDMCHSR_IBE;
> +	val &= ~PCIEDMCHSR_CHTC;
> +

Can you use bitfield operations everywhere?

> +	rcar_pci_write_reg(pcie, val, PCIEDMCHSR(ch));
> +
> +	wmb(); /* flush the settings */

Since the write is at the end of the function, no need to put a barrier here.

> +}
> +
> +static void rcar_pcie_ep_execute_dmac_request(struct rcar_pcie_endpoint *ep,
> +					      enum pci_epf_xfr_direction dir, u8 ch)
> +{
> +	struct rcar_pcie *pcie = &ep->pcie;
> +	u32 val;
> +
> +	/* Enable DMA */
> +	val = rcar_pci_read_reg(pcie, PCIEDMAOR);
> +	val |= PCIEDMAOR_DMAE;
> +	rcar_pci_write_reg(pcie, val, PCIEDMAOR);
> +
> +	/* Configure the DMA direction */
> +	val = rcar_pci_read_reg(pcie, PCIEDMCHCR(ch));
> +	if (dir == INTERNAL_TO_PCIE)
> +		val |= PCIEDMCHCR_DIR;
> +	else
> +		val &= ~PCIEDMCHCR_DIR;
> +
> +	val |= PCIEDMCHCR_CHE;
> +	rcar_pci_write_reg(pcie, val, PCIEDMCHCR(ch));
> +
> +	wmb(); /* flush the settings */

Same here.

> +}
> +
> +static enum rcar_pcie_ep_dmac_xfr_status
> +rcar_pcie_ep_get_dmac_status(struct rcar_pcie_endpoint *ep,
> +			     size_t *count, u8 ch)

ch is unused.

> +{
> +	*count = ep->xfr.bytes;
> +	return ep->xfr.status;
> +}
> +
> +static void rcar_pcie_ep_stop_dmac_request(struct rcar_pcie_endpoint *ep, u8 ch)
> +{
> +	struct rcar_pcie *pcie = &ep->pcie;
> +	u32 val;
> +
> +	val = rcar_pci_read_reg(pcie, PCIEDMCHCR(ch));
> +	val &= ~PCIEDMCHCR_CHE;
> +	rcar_pci_write_reg(pcie, val, PCIEDMCHCR(ch));
> +
> +	/* Disable interrupt */
> +	val = rcar_pci_read_reg(pcie, PCIEDMAOR);
> +	val &= ~PCIEDMAOR_DMAE;
> +	rcar_pci_write_reg(pcie, val, PCIEDMAOR);
> +}
> +
>  static void rcar_pcie_ep_hw_init(struct rcar_pcie *pcie)
>  {
>  	u32 val;
> @@ -419,6 +540,44 @@ static int rcar_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, u8 vfn,
>  	}
>  }
>  
> +static int rcar_pcie_ep_data_transfer(struct pci_epc *epc, struct pci_epf *epf,
> +				      dma_addr_t dma_dst, dma_addr_t dma_src,
> +				      size_t len, enum pci_epf_xfr_direction dir)
> +{
> +	struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
> +	u8 ch = RCAR_PCIE_DMAC_DEFAULT_CHANNEL;
> +	enum rcar_pcie_ep_dmac_xfr_status stat;
> +	int ret = -EINVAL;
> +	long wait_status;
> +	size_t count;
> +
> +	if (len > RCAR_PCIE_MAX_DMAC_BYTE_COUNT ||
> +	    (len % RCAR_PCIE_DMAC_BYTE_COUNT_MULTIPLE) != 0)
> +		return -EINVAL;

A comment here would be informative.

> +
> +	if (mutex_is_locked(&ep->dma_operation) || rcar_pcie_ep_is_dmac_active(ep))

Why the mutex should be checked here? Why can't this thread sleep below if mutex
is not available?

> +		return -EBUSY;
> +
> +	mutex_lock(&ep->dma_operation);
> +
> +	rcar_pcie_ep_setup_dmac_request(ep, dma_dst, dma_src, len, dir, ch);
> +
> +	rcar_pcie_ep_execute_dmac_request(ep, dir, ch);
> +
> +	wait_status = wait_for_completion_interruptible_timeout(&ep->irq_raised,
> +								RCAR_PCIE_DMAC_TIMEOUT);
> +	if (wait_status <= 0) {
> +		rcar_pcie_ep_stop_dmac_request(ep, ch);

ret = -ETIMEDOUT;?

> +	} else {
> +		stat = rcar_pcie_ep_get_dmac_status(ep, &count, ch);
> +		if (stat == RCAR_PCIE_DMA_XFR_SUCCESS && !count)
> +			ret = 0;
> +	}
> +
> +	mutex_unlock(&ep->dma_operation);
> +	return ret;
> +}
> +
>  static int rcar_pcie_ep_start(struct pci_epc *epc)
>  {
>  	struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
> @@ -429,6 +588,55 @@ static int rcar_pcie_ep_start(struct pci_epc *epc)
>  	return 0;
>  }
>  
> +static irqreturn_t rcar_pcie_ep_dmac_irq_handler(int irq, void *arg)
> +{
> +	u8 ch = RCAR_PCIE_DMAC_DEFAULT_CHANNEL;
> +	struct rcar_pcie_endpoint *ep = arg;
> +	struct rcar_pcie *pcie = &ep->pcie;
> +	unsigned long flags;
> +	u32 chsr_val;
> +	u32 chcr_val;
> +	u32 bytes;
> +
> +	spin_lock_irqsave(&ep->lock, flags);

Since the lock is taken in isr, there is no need to do irqsave/restore.
Just spin_lock/unlock is enough.

Also, this lock is only used in isr. I'm wondering why the lock is needed.

> +
> +	chsr_val = rcar_pci_read_reg(pcie, PCIEDMCHSR(ch));
> +
> +	chcr_val = rcar_pci_read_reg(pcie, PCIEDMCHCR(ch));
> +
> +	if (mutex_is_locked(&ep->dma_operation)) {

Why should the mutex be checked? Are you expecting the irq after transfer
timeout?

> +		if ((chsr_val &  PCIEDMCHSR_PEE) ||
> +		    (chsr_val & PCIEDMCHSR_IBE) ||
> +		    (chsr_val & PCIEDMCHSR_CHTC))
> +			ep->xfr.status = RCAR_PCIE_DMA_XFR_ERROR;
> +		else if (chsr_val & PCIEDMCHSR_TE)
> +			ep->xfr.status = RCAR_PCIE_DMA_XFR_SUCCESS;
> +
> +		/* get byte count */
> +		bytes = rcar_pci_read_reg(pcie, PCIEDMBCNTR(ch));
> +		ep->xfr.bytes = bytes;
> +
> +		if ((chsr_val & PCIEDMCHSR_PEE) || (chsr_val & PCIEDMCHSR_IBE) ||
> +		    (chsr_val & PCIEDMCHSR_TE) || (chsr_val & PCIEDMCHSR_CHTC)) {
> +			complete(&ep->irq_raised);
> +		}
> +	} else {
> +		spin_unlock_irqrestore(&ep->lock, flags);
> +		return IRQ_NONE;
> +	}
> +
> +	if (chcr_val & PCIEDMCHCR_CHE)
> +		chcr_val &= ~PCIEDMCHCR_CHE;
> +	rcar_pci_write_reg(pcie, chcr_val, PCIEDMCHCR(ch));
> +
> +	/* Clear DMA interrupt source */
> +	rcar_pci_write_reg(pcie, chsr_val, PCIEDMCHSR(ch));
> +
> +	spin_unlock_irqrestore(&ep->lock, flags);
> +
> +	return IRQ_HANDLED;
> +}
> +
>  static void rcar_pcie_ep_stop(struct pci_epc *epc)
>  {
>  	struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
> @@ -446,6 +654,8 @@ static const struct pci_epc_features rcar_pcie_epc_features = {
>  	.bar_fixed_size[0] = 128,
>  	.bar_fixed_size[2] = 256,
>  	.bar_fixed_size[4] = 256,
> +	.internal_dmac = true,
> +	.internal_dmac_mask = DMA_BIT_MASK(32),
>  };
>  
>  static const struct pci_epc_features*
> @@ -466,6 +676,7 @@ static const struct pci_epc_ops rcar_pcie_epc_ops = {
>  	.start		= rcar_pcie_ep_start,
>  	.stop		= rcar_pcie_ep_stop,
>  	.get_features	= rcar_pcie_ep_get_features,
> +	.dmac_transfer	= rcar_pcie_ep_data_transfer,
>  };
>  
>  static const struct of_device_id rcar_pcie_ep_of_match[] = {
> @@ -480,6 +691,7 @@ static int rcar_pcie_ep_probe(struct platform_device *pdev)
>  	struct rcar_pcie_endpoint *ep;
>  	struct rcar_pcie *pcie;
>  	struct pci_epc *epc;
> +	int dmac_irq;
>  	int err;
>  
>  	ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
> @@ -502,6 +714,14 @@ static int rcar_pcie_ep_probe(struct platform_device *pdev)
>  		goto err_pm_put;
>  	}
>  
> +	dmac_irq = platform_get_irq(pdev, 1);
> +	if (dmac_irq < 0)

"err = dmac_irq" or just use "err".

Thanks,
Mani
> +		goto err_pm_put;
> +
> +	init_completion(&ep->irq_raised);
> +	mutex_init(&ep->dma_operation);
> +	spin_lock_init(&ep->lock);
> +
>  	ep->num_ib_windows = MAX_NR_INBOUND_MAPS;
>  	ep->ib_window_map =
>  			devm_kcalloc(dev, BITS_TO_LONGS(ep->num_ib_windows),
> @@ -533,6 +753,13 @@ static int rcar_pcie_ep_probe(struct platform_device *pdev)
>  
>  	rcar_pcie_ep_hw_init(pcie);
>  
> +	err = devm_request_irq(dev, dmac_irq, rcar_pcie_ep_dmac_irq_handler,
> +			       0, "pcie-rcar-ep-dmac", pcie);
> +	if (err) {
> +		dev_err(dev, "failed to request dmac irq\n");
> +		goto err_pm_put;
> +	}
> +
>  	err = pci_epc_multi_mem_init(epc, ep->ob_window, ep->num_ob_windows);
>  	if (err < 0) {
>  		dev_err(dev, "failed to initialize the epc memory space\n");
> diff --git a/drivers/pci/controller/pcie-rcar.h b/drivers/pci/controller/pcie-rcar.h
> index 9bb125db85c6..874f8a384e6d 100644
> --- a/drivers/pci/controller/pcie-rcar.h
> +++ b/drivers/pci/controller/pcie-rcar.h
> @@ -54,6 +54,29 @@
>  #define  PAR_ENABLE		BIT(31)
>  #define  IO_SPACE		BIT(8)
>  
> +/* PCIe DMAC control reg & mask */
> +#define PCIEDMAOR		0x04000
> +#define  PCIEDMAOR_DMAE		BIT(31)
> +#define  PCIEDMAOR_DMAACT	BIT(16)
> +#define PCIEDMPALR(x)		(0x04100 + ((x) * 0x40))
> +#define PCIEDMPAUR(x)		(0x04104 + ((x) * 0x40))
> +#define PCIEDMIAR(x)		(0x04108 + ((x) * 0x40))
> +#define PCIEDMBCNTR(x)		(0x04110 + ((x) * 0x40))
> +#define PCIEDMCCAR(x)		(0x04120 + ((x) * 0x40))
> +#define PCIEDMCHCR(x)		(0x04128 + ((x) * 0x40))
> +#define  PCIEDMCHCR_CHE		BIT(31)
> +#define  PCIEDMCHCR_DIR		BIT(30)
> +#define PCIEDMCHSR(x)		(0x0412c + ((x) * 0x40))
> +#define  PCIEDMCHSR_CHTCE	BIT(28)
> +#define  PCIEDMCHSR_PEEE	BIT(27)
> +#define  PCIEDMCHSR_IBEE	BIT(25)
> +#define  PCIEDMCHSR_CHTC	BIT(12)
> +#define  PCIEDMCHSR_PEE		BIT(11)
> +#define  PCIEDMCHSR_IBE		BIT(9)
> +#define  PCIEDMCHSR_IE		BIT(3)
> +#define  PCIEDMCHSR_TE		BIT(0)
> +#define PCIEDMCHC2R(x)		(0x04130 + ((x) * 0x40))
> +
>  /* Configuration */
>  #define PCICONF(x)		(0x010000 + ((x) * 0x4))
>  #define  INTDIS			BIT(10)
> -- 
> 2.25.1
> 

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

* Re: [EXT] [RFC PATCH 5/5] PCI: rcar-ep: Add support for DMAC
  2022-01-26 19:50 ` [RFC PATCH 5/5] PCI: rcar-ep: Add support for DMAC Lad Prabhakar
  2022-02-14 10:40   ` Manivannan Sadhasivam
@ 2022-02-21  4:32   ` Li Chen
  1 sibling, 0 replies; 21+ messages in thread
From: Li Chen @ 2022-02-21  4:32 UTC (permalink / raw)
  To: Lad Prabhakar
  Cc: Kishon Vijay Abraham I, Bjorn Helgaas, Lorenzo Pieralisi,
	"Krzysztof Wilczyński",
	Arnd Bergmann, Greg Kroah-Hartman, Marek Vasut,
	Yoshihiro Shimoda, Rob Herring, linux-pci, linux-renesas-soc,
	linux-kernel, Prabhakar, Biju Das

Hi Prabhakar,

I have two questions:
1. You provide both INTERNAL_TO_PCIE and PCIE_TO_INTERNAL, does it mean rcar's IP can do R/W outbound DMA and R/W inbound DMA? As I know, some PCIe's controllers can only issue read requests for inbound DMA and write requests for outbound DMA, I wonder does rcar has this limitation?
2. You only provide DMAc support for EP, is it possible to use internal DMAC on RC, like read/write EP's bar using RC's internal DMAC?

Regards,
Li

 ---- On Thu, 27 Jan 2022 03:50:43 +0800 Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com> wrote ----
 > R-Car PCIe controller has an internal DMAC to support data transfer
 > between Internal Bus -> PCI Express and vice versa.
 > 
 > This patch fills in the required flags and ops for the PCIe EP to
 > support DMAC transfer.
 > 
 > Signed-off-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
 > ---
 >  drivers/pci/controller/pcie-rcar-ep.c | 227 ++++++++++++++++++++++++++
 >  drivers/pci/controller/pcie-rcar.h    |  23 +++
 >  2 files changed, 250 insertions(+)
 > 
 > diff --git a/drivers/pci/controller/pcie-rcar-ep.c b/drivers/pci/controller/pcie-rcar-ep.c
 > index f9682df1da61..c49b25069328 100644
 > --- a/drivers/pci/controller/pcie-rcar-ep.c
 > +++ b/drivers/pci/controller/pcie-rcar-ep.c
 > @@ -18,6 +18,21 @@
 >  
 >  #define RCAR_EPC_MAX_FUNCTIONS        1
 >  
 > +#define RCAR_PCIE_MAX_DMAC_BYTE_COUNT        0x7FFFFFFU
 > +#define RCAR_PCIE_DMAC_BYTE_COUNT_MULTIPLE    8
 > +#define RCAR_PCIE_DMAC_TIMEOUT            (msecs_to_jiffies(3 * 1000))
 > +#define RCAR_PCIE_DMAC_DEFAULT_CHANNEL        0
 > +
 > +enum rcar_pcie_ep_dmac_xfr_status {
 > +    RCAR_PCIE_DMA_XFR_SUCCESS,
 > +    RCAR_PCIE_DMA_XFR_ERROR,
 > +};
 > +
 > +struct rcar_pcie_ep_dmac_info {
 > +    enum rcar_pcie_ep_dmac_xfr_status status;
 > +    size_t bytes;
 > +};
 > +
 >  /* Structure representing the PCIe interface */
 >  struct rcar_pcie_endpoint {
 >      struct rcar_pcie    pcie;
 > @@ -28,8 +43,114 @@ struct rcar_pcie_endpoint {
 >      unsigned long        *ib_window_map;
 >      u32            num_ib_windows;
 >      u32            num_ob_windows;
 > +    struct completion    irq_raised;
 > +    struct mutex        dma_operation;
 > +    spinlock_t        lock;
 > +    struct rcar_pcie_ep_dmac_info xfr;
 >  };
 >  
 > +static inline bool rcar_pcie_ep_is_dmac_active(struct rcar_pcie_endpoint *ep)
 > +{
 > +    if (rcar_pci_read_reg(&ep->pcie, PCIEDMAOR) & PCIEDMAOR_DMAACT)
 > +        return true;
 > +
 > +    return false;
 > +}
 > +
 > +static void
 > +rcar_pcie_ep_setup_dmac_request(struct rcar_pcie_endpoint *ep,
 > +                dma_addr_t dma_dst, dma_addr_t dma_src,
 > +                size_t len, enum pci_epf_xfr_direction dir, u8 ch)
 > +{
 > +    struct rcar_pcie *pcie = &ep->pcie;
 > +    u32 val;
 > +
 > +    ep->xfr.status = RCAR_PCIE_DMA_XFR_ERROR;
 > +    ep->xfr.bytes = RCAR_PCIE_MAX_DMAC_BYTE_COUNT;
 > +
 > +    /* swap values if xfr is from pcie to internal */
 > +    if (dir == PCIE_TO_INTERNAL)
 > +        swap(dma_dst, dma_src);
 > +
 > +    /* Configure the PCI Express lower */
 > +    rcar_pci_write_reg(pcie, lower_32_bits(dma_dst), PCIEDMPALR(ch));
 > +
 > +    /* Configure the PCI Express upper */
 > +    rcar_pci_write_reg(pcie, upper_32_bits(dma_dst), PCIEDMPAUR(ch));
 > +
 > +    /* Configure the internal bus address */
 > +    rcar_pci_write_reg(pcie, lower_32_bits(dma_src), PCIEDMIAR(ch));
 > +
 > +    /* Configure the byte count values */
 > +    rcar_pci_write_reg(pcie, len, PCIEDMBCNTR(ch));
 > +
 > +    /* Enable interrupts */
 > +    val = rcar_pci_read_reg(pcie, PCIEDMCHSR(ch));
 > +
 > +    /* set enable flags */
 > +    val |= PCIEDMCHSR_IE;
 > +    val |= PCIEDMCHSR_IBEE;
 > +    val |= PCIEDMCHSR_PEEE;
 > +    val |= PCIEDMCHSR_CHTCE;
 > +
 > +    /* Clear error flags */
 > +    val &= ~PCIEDMCHSR_TE;
 > +    val &= ~PCIEDMCHSR_PEE;
 > +    val &= ~PCIEDMCHSR_IBE;
 > +    val &= ~PCIEDMCHSR_CHTC;
 > +
 > +    rcar_pci_write_reg(pcie, val, PCIEDMCHSR(ch));
 > +
 > +    wmb(); /* flush the settings */
 > +}
 > +
 > +static void rcar_pcie_ep_execute_dmac_request(struct rcar_pcie_endpoint *ep,
 > +                          enum pci_epf_xfr_direction dir, u8 ch)
 > +{
 > +    struct rcar_pcie *pcie = &ep->pcie;
 > +    u32 val;
 > +
 > +    /* Enable DMA */
 > +    val = rcar_pci_read_reg(pcie, PCIEDMAOR);
 > +    val |= PCIEDMAOR_DMAE;
 > +    rcar_pci_write_reg(pcie, val, PCIEDMAOR);
 > +
 > +    /* Configure the DMA direction */
 > +    val = rcar_pci_read_reg(pcie, PCIEDMCHCR(ch));
 > +    if (dir == INTERNAL_TO_PCIE)
 > +        val |= PCIEDMCHCR_DIR;
 > +    else
 > +        val &= ~PCIEDMCHCR_DIR;
 > +
 > +    val |= PCIEDMCHCR_CHE;
 > +    rcar_pci_write_reg(pcie, val, PCIEDMCHCR(ch));
 > +
 > +    wmb(); /* flush the settings */
 > +}
 > +
 > +static enum rcar_pcie_ep_dmac_xfr_status
 > +rcar_pcie_ep_get_dmac_status(struct rcar_pcie_endpoint *ep,
 > +                 size_t *count, u8 ch)
 > +{
 > +    *count = ep->xfr.bytes;
 > +    return ep->xfr.status;
 > +}
 > +
 > +static void rcar_pcie_ep_stop_dmac_request(struct rcar_pcie_endpoint *ep, u8 ch)
 > +{
 > +    struct rcar_pcie *pcie = &ep->pcie;
 > +    u32 val;
 > +
 > +    val = rcar_pci_read_reg(pcie, PCIEDMCHCR(ch));
 > +    val &= ~PCIEDMCHCR_CHE;
 > +    rcar_pci_write_reg(pcie, val, PCIEDMCHCR(ch));
 > +
 > +    /* Disable interrupt */
 > +    val = rcar_pci_read_reg(pcie, PCIEDMAOR);
 > +    val &= ~PCIEDMAOR_DMAE;
 > +    rcar_pci_write_reg(pcie, val, PCIEDMAOR);
 > +}
 > +
 >  static void rcar_pcie_ep_hw_init(struct rcar_pcie *pcie)
 >  {
 >      u32 val;
 > @@ -419,6 +540,44 @@ static int rcar_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn, u8 vfn,
 >      }
 >  }
 >  
 > +static int rcar_pcie_ep_data_transfer(struct pci_epc *epc, struct pci_epf *epf,
 > +                      dma_addr_t dma_dst, dma_addr_t dma_src,
 > +                      size_t len, enum pci_epf_xfr_direction dir)
 > +{
 > +    struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
 > +    u8 ch = RCAR_PCIE_DMAC_DEFAULT_CHANNEL;
 > +    enum rcar_pcie_ep_dmac_xfr_status stat;
 > +    int ret = -EINVAL;
 > +    long wait_status;
 > +    size_t count;
 > +
 > +    if (len > RCAR_PCIE_MAX_DMAC_BYTE_COUNT ||
 > +        (len % RCAR_PCIE_DMAC_BYTE_COUNT_MULTIPLE) != 0)
 > +        return -EINVAL;
 > +
 > +    if (mutex_is_locked(&ep->dma_operation) || rcar_pcie_ep_is_dmac_active(ep))
 > +        return -EBUSY;
 > +
 > +    mutex_lock(&ep->dma_operation);
 > +
 > +    rcar_pcie_ep_setup_dmac_request(ep, dma_dst, dma_src, len, dir, ch);
 > +
 > +    rcar_pcie_ep_execute_dmac_request(ep, dir, ch);
 > +
 > +    wait_status = wait_for_completion_interruptible_timeout(&ep->irq_raised,
 > +                                RCAR_PCIE_DMAC_TIMEOUT);
 > +    if (wait_status <= 0) {
 > +        rcar_pcie_ep_stop_dmac_request(ep, ch);
 > +    } else {
 > +        stat = rcar_pcie_ep_get_dmac_status(ep, &count, ch);
 > +        if (stat == RCAR_PCIE_DMA_XFR_SUCCESS && !count)
 > +            ret = 0;
 > +    }
 > +
 > +    mutex_unlock(&ep->dma_operation);
 > +    return ret;
 > +}
 > +
 >  static int rcar_pcie_ep_start(struct pci_epc *epc)
 >  {
 >      struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
 > @@ -429,6 +588,55 @@ static int rcar_pcie_ep_start(struct pci_epc *epc)
 >      return 0;
 >  }
 >  
 > +static irqreturn_t rcar_pcie_ep_dmac_irq_handler(int irq, void *arg)
 > +{
 > +    u8 ch = RCAR_PCIE_DMAC_DEFAULT_CHANNEL;
 > +    struct rcar_pcie_endpoint *ep = arg;
 > +    struct rcar_pcie *pcie = &ep->pcie;
 > +    unsigned long flags;
 > +    u32 chsr_val;
 > +    u32 chcr_val;
 > +    u32 bytes;
 > +
 > +    spin_lock_irqsave(&ep->lock, flags);
 > +
 > +    chsr_val = rcar_pci_read_reg(pcie, PCIEDMCHSR(ch));
 > +
 > +    chcr_val = rcar_pci_read_reg(pcie, PCIEDMCHCR(ch));
 > +
 > +    if (mutex_is_locked(&ep->dma_operation)) {
 > +        if ((chsr_val &  PCIEDMCHSR_PEE) ||
 > +            (chsr_val & PCIEDMCHSR_IBE) ||
 > +            (chsr_val & PCIEDMCHSR_CHTC))
 > +            ep->xfr.status = RCAR_PCIE_DMA_XFR_ERROR;
 > +        else if (chsr_val & PCIEDMCHSR_TE)
 > +            ep->xfr.status = RCAR_PCIE_DMA_XFR_SUCCESS;
 > +
 > +        /* get byte count */
 > +        bytes = rcar_pci_read_reg(pcie, PCIEDMBCNTR(ch));
 > +        ep->xfr.bytes = bytes;
 > +
 > +        if ((chsr_val & PCIEDMCHSR_PEE) || (chsr_val & PCIEDMCHSR_IBE) ||
 > +            (chsr_val & PCIEDMCHSR_TE) || (chsr_val & PCIEDMCHSR_CHTC)) {
 > +            complete(&ep->irq_raised);
 > +        }
 > +    } else {
 > +        spin_unlock_irqrestore(&ep->lock, flags);
 > +        return IRQ_NONE;
 > +    }
 > +
 > +    if (chcr_val & PCIEDMCHCR_CHE)
 > +        chcr_val &= ~PCIEDMCHCR_CHE;
 > +    rcar_pci_write_reg(pcie, chcr_val, PCIEDMCHCR(ch));
 > +
 > +    /* Clear DMA interrupt source */
 > +    rcar_pci_write_reg(pcie, chsr_val, PCIEDMCHSR(ch));
 > +
 > +    spin_unlock_irqrestore(&ep->lock, flags);
 > +
 > +    return IRQ_HANDLED;
 > +}
 > +
 >  static void rcar_pcie_ep_stop(struct pci_epc *epc)
 >  {
 >      struct rcar_pcie_endpoint *ep = epc_get_drvdata(epc);
 > @@ -446,6 +654,8 @@ static const struct pci_epc_features rcar_pcie_epc_features = {
 >      .bar_fixed_size[0] = 128,
 >      .bar_fixed_size[2] = 256,
 >      .bar_fixed_size[4] = 256,
 > +    .internal_dmac = true,
 > +    .internal_dmac_mask = DMA_BIT_MASK(32),
 >  };
 >  
 >  static const struct pci_epc_features*
 > @@ -466,6 +676,7 @@ static const struct pci_epc_ops rcar_pcie_epc_ops = {
 >      .start        = rcar_pcie_ep_start,
 >      .stop        = rcar_pcie_ep_stop,
 >      .get_features    = rcar_pcie_ep_get_features,
 > +    .dmac_transfer    = rcar_pcie_ep_data_transfer,
 >  };
 >  
 >  static const struct of_device_id rcar_pcie_ep_of_match[] = {
 > @@ -480,6 +691,7 @@ static int rcar_pcie_ep_probe(struct platform_device *pdev)
 >      struct rcar_pcie_endpoint *ep;
 >      struct rcar_pcie *pcie;
 >      struct pci_epc *epc;
 > +    int dmac_irq;
 >      int err;
 >  
 >      ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
 > @@ -502,6 +714,14 @@ static int rcar_pcie_ep_probe(struct platform_device *pdev)
 >          goto err_pm_put;
 >      }
 >  
 > +    dmac_irq = platform_get_irq(pdev, 1);
 > +    if (dmac_irq < 0)
 > +        goto err_pm_put;
 > +
 > +    init_completion(&ep->irq_raised);
 > +    mutex_init(&ep->dma_operation);
 > +    spin_lock_init(&ep->lock);
 > +
 >      ep->num_ib_windows = MAX_NR_INBOUND_MAPS;
 >      ep->ib_window_map =
 >              devm_kcalloc(dev, BITS_TO_LONGS(ep->num_ib_windows),
 > @@ -533,6 +753,13 @@ static int rcar_pcie_ep_probe(struct platform_device *pdev)
 >  
 >      rcar_pcie_ep_hw_init(pcie);
 >  
 > +    err = devm_request_irq(dev, dmac_irq, rcar_pcie_ep_dmac_irq_handler,
 > +                   0, "pcie-rcar-ep-dmac", pcie);
 > +    if (err) {
 > +        dev_err(dev, "failed to request dmac irq\n");
 > +        goto err_pm_put;
 > +    }
 > +
 >      err = pci_epc_multi_mem_init(epc, ep->ob_window, ep->num_ob_windows);
 >      if (err < 0) {
 >          dev_err(dev, "failed to initialize the epc memory space\n");
 > diff --git a/drivers/pci/controller/pcie-rcar.h b/drivers/pci/controller/pcie-rcar.h
 > index 9bb125db85c6..874f8a384e6d 100644
 > --- a/drivers/pci/controller/pcie-rcar.h
 > +++ b/drivers/pci/controller/pcie-rcar.h
 > @@ -54,6 +54,29 @@
 >  #define  PAR_ENABLE        BIT(31)
 >  #define  IO_SPACE        BIT(8)
 >  
 > +/* PCIe DMAC control reg & mask */
 > +#define PCIEDMAOR        0x04000
 > +#define  PCIEDMAOR_DMAE        BIT(31)
 > +#define  PCIEDMAOR_DMAACT    BIT(16)
 > +#define PCIEDMPALR(x)        (0x04100 + ((x) * 0x40))
 > +#define PCIEDMPAUR(x)        (0x04104 + ((x) * 0x40))
 > +#define PCIEDMIAR(x)        (0x04108 + ((x) * 0x40))
 > +#define PCIEDMBCNTR(x)        (0x04110 + ((x) * 0x40))
 > +#define PCIEDMCCAR(x)        (0x04120 + ((x) * 0x40))
 > +#define PCIEDMCHCR(x)        (0x04128 + ((x) * 0x40))
 > +#define  PCIEDMCHCR_CHE        BIT(31)
 > +#define  PCIEDMCHCR_DIR        BIT(30)
 > +#define PCIEDMCHSR(x)        (0x0412c + ((x) * 0x40))
 > +#define  PCIEDMCHSR_CHTCE    BIT(28)
 > +#define  PCIEDMCHSR_PEEE    BIT(27)
 > +#define  PCIEDMCHSR_IBEE    BIT(25)
 > +#define  PCIEDMCHSR_CHTC    BIT(12)
 > +#define  PCIEDMCHSR_PEE        BIT(11)
 > +#define  PCIEDMCHSR_IBE        BIT(9)
 > +#define  PCIEDMCHSR_IE        BIT(3)
 > +#define  PCIEDMCHSR_TE        BIT(0)
 > +#define PCIEDMCHC2R(x)        (0x04130 + ((x) * 0x40))
 > +
 >  /* Configuration */
 >  #define PCICONF(x)        (0x010000 + ((x) * 0x4))
 >  #define  INTDIS            BIT(10)
 > -- 
 > 2.25.1
 > 
 > 
 > ######################################################################
 > This EXTERNAL email has been scanned by Proofpoint Email Protect service.
 > 

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

end of thread, other threads:[~2022-02-21  4:32 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-26 19:50 [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC Lad Prabhakar
2022-01-26 19:50 ` [RFC PATCH 1/5] PCI: endpoint: Add ops and flag to support internal DMAC Lad Prabhakar
2022-02-14  9:30   ` Manivannan Sadhasivam
2022-01-26 19:50 ` [RFC PATCH 2/5] PCI: endpoint: Add support to data transfer using internal dmac Lad Prabhakar
2022-02-14  9:49   ` Manivannan Sadhasivam
2022-01-26 19:50 ` [RFC PATCH 3/5] misc: pci_endpoint_test: Add driver data for Renesas RZ/G2{EHMN} Lad Prabhakar
2022-02-14 10:02   ` Manivannan Sadhasivam
2022-01-26 19:50 ` [RFC PATCH 4/5] misc: pci_endpoint_test: Add support to pass flags for buffer allocation Lad Prabhakar
2022-02-14 10:11   ` Manivannan Sadhasivam
2022-01-26 19:50 ` [RFC PATCH 5/5] PCI: rcar-ep: Add support for DMAC Lad Prabhakar
2022-02-14 10:40   ` Manivannan Sadhasivam
2022-02-21  4:32   ` [EXT] " Li Chen
2022-02-09  4:47 ` [EXT] [RFC PATCH 0/5] PCIe EPF support for internal DMAC handling and driver update for R-Car PCIe EP to support DMAC Li Chen
2022-02-09  8:52   ` Lad, Prabhakar
2022-02-10  5:54     ` Li Chen
2022-02-10  7:47       ` Greg Kroah-Hartman
2022-02-10  8:40 ` Manivannan Sadhasivam
2022-02-10  9:24   ` Lad, Prabhakar
2022-02-10 10:50     ` Manivannan Sadhasivam
2022-02-10 11:05       ` Lad, Prabhakar
2022-02-10 13:22         ` 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).