diff mbox series

[v15,08/22] PCI: designware-ep: Add INTx IRQs support

Message ID 20230509124156.150200-9-yoshihiro.shimoda.uh@renesas.com
State New
Headers show
Series PCI: rcar-gen4: Add R-Car Gen4 PCIe support | expand

Commit Message

Yoshihiro Shimoda May 9, 2023, 12:41 p.m. UTC
Add support for triggering INTx IRQs by using outbound iATU.
Outbound iATU is utilized to send assert and de-assert INTx TLPs.
The message is generated based on the payloadless Msg TLP with type
0x14, where 0x4 is the routing code implying the Terminate at
Receiver message. The message code is specified as b1000xx for
the INTx assertion and b1001xx for the INTx de-assertion.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
 .../pci/controller/dwc/pcie-designware-ep.c   | 65 +++++++++++++++++--
 drivers/pci/controller/dwc/pcie-designware.h  |  2 +
 2 files changed, 63 insertions(+), 4 deletions(-)

Comments

Frank Li May 9, 2023, 1:59 p.m. UTC | #1
> -       return -EINVAL;
> +       ret = dw_pcie_ep_send_msg(ep, func_no, PCI_CODE_ASSERT_INTA,
> +                                 PCI_MSG_ROUTING_LOCAL);
> +       if (ret)
> +               return ret;
> +
> +       /*
> +        * The documents of PCIe and the controller don't mention how long
> +        * the INTx should be asserted. If 10 usec, sometimes it failed.
> +        * So, asserted for 50 usec.
> +        */
> +       usleep_range(50, 100);

[Frank Li] At least, comments should be updated. It should be level irq. 
Here is edge trigger because frame still not supported yet.  Will improve
Later or some things. Otherwise comments is misleading.

> +
> +       return dw_pcie_ep_send_msg(ep, func_no,
> PCI_CODE_DEASSERT_INTA,
> +                                  PCI_MSG_ROUTING_LOCAL);
>  }
Yoshihiro Shimoda May 10, 2023, 12:03 a.m. UTC | #2
Hi Frank,

> From: Frank Li, Sent: Tuesday, May 9, 2023 11:00 PM
> 
> > -       return -EINVAL;
> > +       ret = dw_pcie_ep_send_msg(ep, func_no, PCI_CODE_ASSERT_INTA,
> > +                                 PCI_MSG_ROUTING_LOCAL);
> > +       if (ret)
> > +               return ret;
> > +
> > +       /*
> > +        * The documents of PCIe and the controller don't mention how long
> > +        * the INTx should be asserted. If 10 usec, sometimes it failed.
> > +        * So, asserted for 50 usec.
> > +        */
> > +       usleep_range(50, 100);
> 
> [Frank Li] At least, comments should be updated. It should be level irq.
> Here is edge trigger because frame still not supported yet.  Will improve
> Later or some things. Otherwise comments is misleading.

Thank you for your comment! I think so. I'll update the comments on v16.

Best regards,
Yoshihiro Shimoda

> > +
> > +       return dw_pcie_ep_send_msg(ep, func_no,
> > PCI_CODE_DEASSERT_INTA,
> > +                                  PCI_MSG_ROUTING_LOCAL);
> >  }
diff mbox series

Patch

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index fe2e0d765be9..3ce83a7532a3 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -6,9 +6,11 @@ 
  * Author: Kishon Vijay Abraham I <kishon@ti.com>
  */
 
+#include <linux/delay.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 
+#include "../../pci.h"
 #include "pcie-designware.h"
 #include <linux/pci-epc.h>
 #include <linux/pci-epf.h>
@@ -484,14 +486,56 @@  static const struct pci_epc_ops epc_ops = {
 	.get_features		= dw_pcie_ep_get_features,
 };
 
+static int dw_pcie_ep_send_msg(struct dw_pcie_ep *ep, u8 func_no, u8 code,
+			       u8 routing)
+{
+	struct dw_pcie_ob_atu_cfg atu = { 0 };
+	struct pci_epc *epc = ep->epc;
+	int ret;
+
+	atu.func_no = func_no;
+	atu.code = code;
+	atu.routing = routing;
+	atu.type = PCIE_ATU_TYPE_MSG;
+	atu.cpu_addr = ep->intx_mem_phys;
+	atu.size = epc->mem->window.page_size;
+
+	ret = dw_pcie_ep_outbound_atu(ep, &atu);
+	if (ret)
+		return ret;
+
+	writel(0, ep->intx_mem);
+
+	dw_pcie_ep_unmap_addr(epc, func_no, 0, ep->intx_mem_phys);
+
+	return 0;
+}
+
 int dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no)
 {
 	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
 	struct device *dev = pci->dev;
+	int ret;
 
-	dev_err(dev, "EP cannot trigger INTx IRQs\n");
+	if (!ep->intx_mem) {
+		dev_err(dev, "INTx not supported\n");
+		return -EOPNOTSUPP;
+	}
 
-	return -EINVAL;
+	ret = dw_pcie_ep_send_msg(ep, func_no, PCI_CODE_ASSERT_INTA,
+				  PCI_MSG_ROUTING_LOCAL);
+	if (ret)
+		return ret;
+
+	/*
+	 * The documents of PCIe and the controller don't mention how long
+	 * the INTx should be asserted. If 10 usec, sometimes it failed.
+	 * So, asserted for 50 usec.
+	 */
+	usleep_range(50, 100);
+
+	return dw_pcie_ep_send_msg(ep, func_no, PCI_CODE_DEASSERT_INTA,
+				   PCI_MSG_ROUTING_LOCAL);
 }
 EXPORT_SYMBOL_GPL(dw_pcie_ep_raise_intx_irq);
 
@@ -622,6 +666,10 @@  void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
 
 	dw_pcie_edma_remove(pci);
 
+	if (ep->intx_mem)
+		pci_epc_mem_free_addr(epc, ep->intx_mem_phys, ep->intx_mem,
+				      epc->mem->window.page_size);
+
 	pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
 			      epc->mem->window.page_size);
 
@@ -793,9 +841,14 @@  int dw_pcie_ep_init(struct dw_pcie_ep *ep)
 		goto err_exit_epc_mem;
 	}
 
+	ep->intx_mem = pci_epc_mem_alloc_addr(epc, &ep->intx_mem_phys,
+					      epc->mem->window.page_size);
+	if (!ep->intx_mem)
+		dev_warn(dev, "Failed to reserve memory for INTx\n");
+
 	ret = dw_pcie_edma_detect(pci);
 	if (ret)
-		goto err_free_epc_mem;
+		goto err_free_epc_mem_intx;
 
 	if (ep->ops->get_features) {
 		epc_features = ep->ops->get_features(ep);
@@ -812,7 +865,11 @@  int dw_pcie_ep_init(struct dw_pcie_ep *ep)
 err_remove_edma:
 	dw_pcie_edma_remove(pci);
 
-err_free_epc_mem:
+err_free_epc_mem_intx:
+	if (ep->intx_mem)
+		pci_epc_mem_free_addr(epc, ep->intx_mem_phys, ep->intx_mem,
+				      epc->mem->window.page_size);
+
 	pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
 			      epc->mem->window.page_size);
 
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index c83d1d176e62..06e044e2163a 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -369,6 +369,8 @@  struct dw_pcie_ep {
 	unsigned long		*ob_window_map;
 	void __iomem		*msi_mem;
 	phys_addr_t		msi_mem_phys;
+	void __iomem		*intx_mem;
+	phys_addr_t		intx_mem_phys;
 	struct pci_epf_bar	*epf_bar[PCI_STD_NUM_BARS];
 };