From patchwork Tue Apr 18 12:23:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yoshihiro Shimoda X-Patchwork-Id: 674676 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id F29C2C77B7D for ; Tue, 18 Apr 2023 12:25:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231324AbjDRMZJ (ORCPT ); Tue, 18 Apr 2023 08:25:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33502 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231222AbjDRMZI (ORCPT ); Tue, 18 Apr 2023 08:25:08 -0400 Received: from relmlie6.idc.renesas.com (relmlor2.renesas.com [210.160.252.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id A9C157ABC; Tue, 18 Apr 2023 05:24:45 -0700 (PDT) X-IronPort-AV: E=Sophos;i="5.99,207,1677510000"; d="scan'208";a="159867440" Received: from unknown (HELO relmlir6.idc.renesas.com) ([10.200.68.152]) by relmlie6.idc.renesas.com with ESMTP; 18 Apr 2023 21:24:14 +0900 Received: from localhost.localdomain (unknown [10.166.15.32]) by relmlir6.idc.renesas.com (Postfix) with ESMTP id 23D65423C45D; Tue, 18 Apr 2023 21:24:14 +0900 (JST) From: Yoshihiro Shimoda To: jingoohan1@gmail.com, mani@kernel.org, gustavo.pimentel@synopsys.com, fancer.lancer@gmail.com, lpieralisi@kernel.org, robh+dt@kernel.org, kw@linux.com, bhelgaas@google.com, kishon@kernel.org Cc: marek.vasut+renesas@gmail.com, linux-pci@vger.kernel.org, devicetree@vger.kernel.org, linux-renesas-soc@vger.kernel.org, Yoshihiro Shimoda Subject: [PATCH v13 09/22] PCI: dwc: Add support for triggering INTx IRQs Date: Tue, 18 Apr 2023 21:23:50 +0900 Message-Id: <20230418122403.3178462-10-yoshihiro.shimoda.uh@renesas.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230418122403.3178462-1-yoshihiro.shimoda.uh@renesas.com> References: <20230418122403.3178462-1-yoshihiro.shimoda.uh@renesas.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org 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 --- .../pci/controller/dwc/pcie-designware-ep.c | 70 +++++++++++++++++-- drivers/pci/controller/dwc/pcie-designware.h | 2 + 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 96375b0aba82..304ed093f551 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -6,6 +6,7 @@ * Author: Kishon Vijay Abraham I */ +#include #include #include @@ -485,14 +486,62 @@ 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_outbound_atu 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; +} + +static int __dw_pcie_ep_raise_intx_irq(struct dw_pcie_ep *ep, u8 func_no, + int intx) +{ + int ret; + + ret = dw_pcie_ep_send_msg(ep, func_no, PCI_CODE_ASSERT_INTA + intx, + 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 + intx, + PCI_MSG_ROUTING_LOCAL); +} + 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; - dev_err(dev, "EP cannot trigger INTx IRQs\n"); + if (!ep->intx_mem) { + dev_err(dev, "EP cannot trigger INTx IRQs\n"); + return -EINVAL; + } - return -EINVAL; + return __dw_pcie_ep_raise_intx_irq(ep, func_no, 0); } EXPORT_SYMBOL_GPL(dw_pcie_ep_raise_intx_irq); @@ -623,6 +672,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); @@ -794,9 +847,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); @@ -813,7 +871,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 954d504890a1..8c08159ea08e 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]; };