From patchwork Fri Jun 10 08:44:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 580851 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 9EF53C43334 for ; Fri, 10 Jun 2022 08:45:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348097AbiFJIpI (ORCPT ); Fri, 10 Jun 2022 04:45:08 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37140 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348067AbiFJIo6 (ORCPT ); Fri, 10 Jun 2022 04:44:58 -0400 Received: from mail.baikalelectronics.com (mail.baikalelectronics.com [87.245.175.230]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 285E3377EF; Fri, 10 Jun 2022 01:44:52 -0700 (PDT) Received: from mail (mail.baikal.int [192.168.51.25]) by mail.baikalelectronics.com (Postfix) with ESMTP id EF19D16A4; Fri, 10 Jun 2022 11:45:38 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.baikalelectronics.com EF19D16A4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baikalelectronics.ru; s=mail; t=1654850738; bh=ORL4JApRjPpGjKJygzUfGiBMxpJLe/dPuqUMZiuGF94=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=r7D3IlBNpYGrn2Wcfw3o01r02rdHcCq3TvLCIQFCptlrWjBFRAcVF3maw1DTHVP/V Sln5kjA4pC8Dz1OSX09SbrSYc8fLmDqNzztjBQaObjUwVjkTfQr+0iEhgwoPbtqRTD BqaVp5qvUREzqMrbtoV5vY/U2nNJtloe8fA4lLh0= Received: from localhost (192.168.53.207) by mail (192.168.51.25) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 10 Jun 2022 11:44:46 +0300 From: Serge Semin To: Rob Herring , Bjorn Helgaas , Lorenzo Pieralisi , Jingoo Han , Gustavo Pimentel , =?utf-8?q?Krzysztof_Wilcz?= =?utf-8?q?y=C5=84ski?= CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Frank Li , Manivannan Sadhasivam , Rob Herring , , , Subject: [PATCH v3 02/15] PCI: dwc: Detect iATU settings after getting "addr_space" resource Date: Fri, 10 Jun 2022 11:44:30 +0300 Message-ID: <20220610084444.14549-3-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20220610084444.14549-1-Sergey.Semin@baikalelectronics.ru> References: <20220610084444.14549-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org The iATU detection procedure was introduced in the commit 281f1f99cf3a ("PCI: dwc: Detect number of iATU windows"). A bit later the procedure execution was moved to Host/EP-specific methods in the framework of commit 8bcca2658558 ("PCI: dwc: Move iATU detection earlier"). The later modification wasn't done in the most optimal way since the "addr_space" CSR region resource doesn't depend on anything detected in the dw_pcie_iatu_detect() method. Thus the detection can be postponed to be executed after the resource request which can fail and make the detection pointless. It will be also helpful for the dw_pcie_ep_init() method readability since we are about to add the IP-core version and eDMA module (a bit later) detection procedures. Signed-off-by: Serge Semin Reviewed-by: Rob Herring --- Changelog v2: - This is a new patch added on v2 iteration of the series. --- drivers/pci/controller/dwc/pcie-designware-ep.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 15b8059544e3..1e35542d6f72 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -704,8 +704,6 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) } } - dw_pcie_iatu_detect(pci); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space"); if (!res) return -EINVAL; @@ -713,6 +711,8 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep) ep->phys_base = res->start; ep->addr_size = resource_size(res); + dw_pcie_iatu_detect(pci); + ep->ib_window_map = devm_kcalloc(dev, BITS_TO_LONGS(pci->num_ib_windows), sizeof(long), From patchwork Fri Jun 10 08:44:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 580850 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 03686C43334 for ; Fri, 10 Jun 2022 08:45:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348088AbiFJIpK (ORCPT ); Fri, 10 Jun 2022 04:45:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37468 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348083AbiFJIpA (ORCPT ); Fri, 10 Jun 2022 04:45:00 -0400 Received: from mail.baikalelectronics.com (mail.baikalelectronics.com [87.245.175.230]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 5680E3980D; Fri, 10 Jun 2022 01:44:59 -0700 (PDT) Received: from mail (mail.baikal.int [192.168.51.25]) by mail.baikalelectronics.com (Postfix) with ESMTP id 78C8E16A7; Fri, 10 Jun 2022 11:45:41 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.baikalelectronics.com 78C8E16A7 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baikalelectronics.ru; s=mail; t=1654850741; bh=9U2WClu82BJWbbQgRZJ1z49ymt89672SnfrQ5iGsWQ8=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=BI0eGAacRV66WdSQ8YWSZHUosIGIFg3NYmzXyS3z05JTkyLaT2QExx4Fx6S7oIOpC vh9BLC7FzgEmHInUtsuqna2uf+Ar8+5VG4ygof3Dfyw6Bsl+01GJEzXFlUgTU6txKG 4D46mbyEvFlM6Pbt1q3/ni8gLK/jg8f3o06hwprM= Received: from localhost (192.168.53.207) by mail (192.168.51.25) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 10 Jun 2022 11:44:49 +0300 From: Serge Semin To: Rob Herring , Bjorn Helgaas , Lorenzo Pieralisi , Jingoo Han , Gustavo Pimentel , =?utf-8?q?Krzysztof_Wilcz?= =?utf-8?q?y=C5=84ski?= CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Frank Li , Manivannan Sadhasivam , Rob Herring , , , Subject: [PATCH v3 05/15] PCI: dwc: Introduce Synopsys IP-core versions/types interface Date: Fri, 10 Jun 2022 11:44:33 +0300 Message-ID: <20220610084444.14549-6-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20220610084444.14549-1-Sergey.Semin@baikalelectronics.ru> References: <20220610084444.14549-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Instead of manual DW PCIe data version field comparison let's use a handy macro-based interface in order to shorten out the statements, simplify the corresponding parts, improve the code readability and maintainability in perspective when more complex version-based dependencies need to implemented. Similar approaches have already been implemented in the DWC USB3 and DW SPI drivers (though with some IP-core evolution specifics). Signed-off-by: Serge Semin Reviewed-by: Rob Herring --- drivers/pci/controller/dwc/pci-keystone.c | 2 +- drivers/pci/controller/dwc/pcie-designware.c | 8 ++++---- drivers/pci/controller/dwc/pcie-designware.h | 15 +++++++++++++++ 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/pci/controller/dwc/pci-keystone.c b/drivers/pci/controller/dwc/pci-keystone.c index c4ab3d775a18..2a9bbde224af 100644 --- a/drivers/pci/controller/dwc/pci-keystone.c +++ b/drivers/pci/controller/dwc/pci-keystone.c @@ -1233,7 +1233,7 @@ static int __init ks_pcie_probe(struct platform_device *pdev) goto err_get_sync; } - if (pci->version >= DW_PCIE_VER_480A) + if (dw_pcie_ver_is_ge(pci, 480A)) ret = ks_pcie_am654_set_mode(dev, mode); else ret = ks_pcie_set_mode(dev); diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index cbb36ccaa48b..bd575ad32bc4 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -313,7 +313,7 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, u8 func_no, val = type | PCIE_ATU_FUNC_NUM(func_no); if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr)) val |= PCIE_ATU_INCREASE_REGION_SIZE; - if (pci->version == DW_PCIE_VER_490A) + if (dw_pcie_ver_is(pci, 490A)) val = dw_pcie_enable_ecrc(val); dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, val); dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, @@ -360,7 +360,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, upper_32_bits(cpu_addr)); dw_pcie_writel_dbi(pci, PCIE_ATU_LIMIT, lower_32_bits(limit_addr)); - if (pci->version >= DW_PCIE_VER_460A) + if (dw_pcie_ver_is_ge(pci, 460A)) dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_LIMIT, upper_32_bits(limit_addr)); dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, @@ -369,9 +369,9 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, upper_32_bits(pci_addr)); val = type | PCIE_ATU_FUNC_NUM(func_no); if (upper_32_bits(limit_addr) > upper_32_bits(cpu_addr) && - pci->version >= DW_PCIE_VER_460A) + dw_pcie_ver_is_ge(pci, 460A)) val |= PCIE_ATU_INCREASE_REGION_SIZE; - if (pci->version == DW_PCIE_VER_490A) + if (dw_pcie_ver_is(pci, 490A)) val = dw_pcie_enable_ecrc(val); dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, val); dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 7899808bdbc6..d247f227464c 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -28,6 +28,21 @@ #define DW_PCIE_VER_490A 0x3439302a #define DW_PCIE_VER_520A 0x3532302a +#define __dw_pcie_ver_cmp(_pci, _ver, _op) \ + ((_pci)->version _op DW_PCIE_VER_ ## _ver) + +#define dw_pcie_ver_is(_pci, _ver) __dw_pcie_ver_cmp(_pci, _ver, ==) + +#define dw_pcie_ver_is_ge(_pci, _ver) __dw_pcie_ver_cmp(_pci, _ver, >=) + +#define dw_pcie_ver_type_is(_pci, _ver, _type) \ + (__dw_pcie_ver_cmp(_pci, _ver, ==) && \ + __dw_pcie_ver_cmp(_pci, TYPE_ ## _type, ==)) + +#define dw_pcie_ver_type_is_ge(_pci, _ver, _type) \ + (__dw_pcie_ver_cmp(_pci, _ver, ==) && \ + __dw_pcie_ver_cmp(_pci, TYPE_ ## _type, >=)) + /* Parameters for the waiting for link up routine */ #define LINK_WAIT_MAX_RETRIES 10 #define LINK_WAIT_USLEEP_MIN 90000 From patchwork Fri Jun 10 08:44:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 580849 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 868EAC43334 for ; Fri, 10 Jun 2022 08:45:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348110AbiFJIpM (ORCPT ); Fri, 10 Jun 2022 04:45:12 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37890 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348091AbiFJIpH (ORCPT ); Fri, 10 Jun 2022 04:45:07 -0400 Received: from mail.baikalelectronics.com (mail.baikalelectronics.com [87.245.175.230]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id A9C793C4A4; Fri, 10 Jun 2022 01:45:03 -0700 (PDT) Received: from mail (mail.baikal.int [192.168.51.25]) by mail.baikalelectronics.com (Postfix) with ESMTP id 5142B16AA; Fri, 10 Jun 2022 11:45:44 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.baikalelectronics.com 5142B16AA DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baikalelectronics.ru; s=mail; t=1654850744; bh=74JObRDPD4kFcRvofWKBybBg4BZsB/S9rb+QiDdcfL4=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=NeU2AF61G7+pVLF23D6yZP8B3oU+Xn6a/+9HVNjnLYvsxOFVPa+pHadV2o6hkRWV9 iZbRwgTvDqjRB1Id1aJ3uvix5/OqTh0r/ca4EJrBPn+m3HrUwzfN/Tic07AskKIo+j h3GM8hGyfT4azQR2592Kym7kmGNS+ePF4I1lAYYM= Received: from localhost (192.168.53.207) by mail (192.168.51.25) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 10 Jun 2022 11:44:52 +0300 From: Serge Semin To: Rob Herring , Bjorn Helgaas , Lorenzo Pieralisi , Jingoo Han , Gustavo Pimentel , =?utf-8?q?Krzysztof_Wilcz?= =?utf-8?q?y=C5=84ski?= CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Frank Li , Manivannan Sadhasivam , Rob Herring , , , Subject: [PATCH v3 09/15] PCI: dwc: Drop inbound iATU types enumeration - dw_pcie_as_type Date: Fri, 10 Jun 2022 11:44:37 +0300 Message-ID: <20220610084444.14549-10-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20220610084444.14549-1-Sergey.Semin@baikalelectronics.ru> References: <20220610084444.14549-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org There is no point in having an enumeration declared in the driver for the PCIe end-point. First of all it's redundant since the driver already has a set of macro declared which describe the available in/out iATU types, thus having an addition abstraction just needlessly complicates the code. Secondly checking the passed iATU type for validity within a single driver is pointless since the driver is supposed to be consistent by its nature. Finally the outbound iATU type isn't encoded by the denoted enumeration, thus giving a false impression that the in and out iATU types are unrelated while they are the same. So to speak let's drop the redundant dw_pcie_as_type enumeration replacing it with the direct iATU type usage. While at it, since we are touching the iATU inbound regions config methods anyway, let's fix the arguments order so the type would be followed by the address-related parameters. Thus the inbound and outbound iATU setup methods will look alike. That shall improve the code readability a bit. Signed-off-by: Serge Semin Reviewed-by: Rob Herring --- .../pci/controller/dwc/pcie-designware-ep.c | 21 +++++------ drivers/pci/controller/dwc/pcie-designware.c | 35 +++---------------- drivers/pci/controller/dwc/pcie-designware.h | 9 +---- 3 files changed, 15 insertions(+), 50 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index ffbd3af6d65a..5a158813f687 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -154,9 +154,8 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no, return 0; } -static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, - enum pci_barno bar, dma_addr_t cpu_addr, - enum dw_pcie_as_type as_type) +static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, int type, + dma_addr_t cpu_addr, enum pci_barno bar) { int ret; u32 free_win; @@ -168,8 +167,8 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, return -EINVAL; } - ret = dw_pcie_prog_inbound_atu(pci, func_no, free_win, bar, cpu_addr, - as_type); + ret = dw_pcie_prog_inbound_atu(pci, func_no, free_win, type, + cpu_addr, bar); if (ret < 0) { dev_err(pci->dev, "Failed to program IB window\n"); return ret; @@ -221,27 +220,25 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, struct pci_epf_bar *epf_bar) { - int ret; struct dw_pcie_ep *ep = epc_get_drvdata(epc); struct dw_pcie *pci = to_dw_pcie_from_ep(ep); enum pci_barno bar = epf_bar->barno; size_t size = epf_bar->size; int flags = epf_bar->flags; - enum dw_pcie_as_type as_type; - u32 reg; unsigned int func_offset = 0; + int ret, type; + u32 reg; func_offset = dw_pcie_ep_func_select(ep, func_no); reg = PCI_BASE_ADDRESS_0 + (4 * bar) + func_offset; if (!(flags & PCI_BASE_ADDRESS_SPACE)) - as_type = DW_PCIE_AS_MEM; + type = PCIE_ATU_TYPE_MEM; else - as_type = DW_PCIE_AS_IO; + type = PCIE_ATU_TYPE_IO; - ret = dw_pcie_ep_inbound_atu(ep, func_no, bar, - epf_bar->phys_addr, as_type); + ret = dw_pcie_ep_inbound_atu(ep, func_no, type, epf_bar->phys_addr, bar); if (ret) return ret; diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index bd575ad32bc4..330575182712 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -421,10 +421,9 @@ static void dw_pcie_writel_ib_unroll(struct dw_pcie *pci, u32 index, u32 reg, } static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no, - int index, int bar, u64 cpu_addr, - enum dw_pcie_as_type as_type) + int index, int type, + u64 cpu_addr, u8 bar) { - int type; u32 retries, val; dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET, @@ -432,17 +431,6 @@ static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no, dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET, upper_32_bits(cpu_addr)); - switch (as_type) { - case DW_PCIE_AS_MEM: - type = PCIE_ATU_TYPE_MEM; - break; - case DW_PCIE_AS_IO: - type = PCIE_ATU_TYPE_IO; - break; - default: - return -EINVAL; - } - dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL1, type | PCIE_ATU_FUNC_NUM(func_no)); dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, @@ -468,32 +456,19 @@ static int dw_pcie_prog_inbound_atu_unroll(struct dw_pcie *pci, u8 func_no, } int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, - int bar, u64 cpu_addr, - enum dw_pcie_as_type as_type) + int type, u64 cpu_addr, u8 bar) { - int type; u32 retries, val; if (pci->iatu_unroll_enabled) - return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, bar, - cpu_addr, as_type); + return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, type, + cpu_addr, bar); dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | index); dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, lower_32_bits(cpu_addr)); dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, upper_32_bits(cpu_addr)); - switch (as_type) { - case DW_PCIE_AS_MEM: - type = PCIE_ATU_TYPE_MEM; - break; - case DW_PCIE_AS_IO: - type = PCIE_ATU_TYPE_IO; - break; - default: - return -EINVAL; - } - dw_pcie_writel_dbi(pci, PCIE_ATU_CR1, type | PCIE_ATU_FUNC_NUM(func_no)); dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, PCIE_ATU_ENABLE | diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 7f1c00fa084d..c63ace3c3f25 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -228,12 +228,6 @@ struct dw_pcie_rp { DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS); }; -enum dw_pcie_as_type { - DW_PCIE_AS_UNKNOWN, - DW_PCIE_AS_MEM, - DW_PCIE_AS_IO, -}; - struct dw_pcie_ep_ops { void (*ep_init)(struct dw_pcie_ep *ep); int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no, @@ -331,8 +325,7 @@ void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, int type, u64 cpu_addr, u64 pci_addr, u64 size); int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, - int bar, u64 cpu_addr, - enum dw_pcie_as_type as_type); + int type, u64 cpu_addr, u8 bar); void dw_pcie_disable_atu(struct dw_pcie *pci, int index, enum dw_pcie_region_type type); void dw_pcie_setup(struct dw_pcie *pci); From patchwork Fri Jun 10 08:44:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 580848 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 82888C43334 for ; Fri, 10 Jun 2022 08:45:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348120AbiFJIpP (ORCPT ); Fri, 10 Jun 2022 04:45:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38158 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348105AbiFJIpO (ORCPT ); Fri, 10 Jun 2022 04:45:14 -0400 Received: from mail.baikalelectronics.com (mail.baikalelectronics.com [87.245.175.230]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 0403A205E3; Fri, 10 Jun 2022 01:45:06 -0700 (PDT) Received: from mail (mail.baikal.int [192.168.51.25]) by mail.baikalelectronics.com (Postfix) with ESMTP id 5623716AD; Fri, 10 Jun 2022 11:45:45 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.baikalelectronics.com 5623716AD DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baikalelectronics.ru; s=mail; t=1654850745; bh=VqF7/VziUOCuXp18Za7SHdom4rV0tJ2cWmO54KkAi1M=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=Zm0BulVltP8+iIl7KTtsIjLnU1lyL/csOq7wFs0GYAhdWqCZ8xbuLBcdreY0q4qrN N97/fU3NCpslwtcfvQu55+ldgYhV3awwLof0GyveHlisZdxTVvR5jO63XVQxSYrwJh NjK9S7EJ8WeJXfllS1E2azxpyN6yDg15uudbqGJI= Received: from localhost (192.168.53.207) by mail (192.168.51.25) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 10 Jun 2022 11:44:52 +0300 From: Serge Semin To: Rob Herring , Bjorn Helgaas , Lorenzo Pieralisi , Jingoo Han , Gustavo Pimentel , =?utf-8?q?Krzysztof_Wilcz?= =?utf-8?q?y=C5=84ski?= CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Frank Li , Manivannan Sadhasivam , Rob Herring , , , Subject: [PATCH v3 10/15] PCI: dwc: Drop iATU regions enumeration - dw_pcie_region_type Date: Fri, 10 Jun 2022 11:44:38 +0300 Message-ID: <20220610084444.14549-11-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20220610084444.14549-1-Sergey.Semin@baikalelectronics.ru> References: <20220610084444.14549-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org There is no point in having the dw_pcie_region_type enumeration for almost the same reasons as it was stated for dw_pcie_as_type. First of all it's redundant since the driver already has a set of the macros declared which describe the possible inbound and outbound iATU regions. Having an addition abstraction just needlessly complicates the code. Secondly checking the region type passed to the dw_pcie_disable_atu() method for validity is pointless since the erroneous situation is just ignored in the current method implementation. So to speak let's drop the redundant dw_pcie_region_type enumeration replacing it with the direct iATU direction macro usage. Since the dw_pcie_disable_atu() method now directly accepts the in-/outbound iATU region direction instead of the abstract region type we need to change the argument name and the arguments order. The later change makes the function prototype looking more logical since the passed index indicates an iATU window within the regions with the corresponding direction. Signed-off-by: Serge Semin Reviewed-by: Rob Herring --- Changelog v2: - Move this patch to being applied before the IB/OB iATU windows setup simplification patch (@Rob). --- .../pci/controller/dwc/pcie-designware-ep.c | 4 +-- .../pci/controller/dwc/pcie-designware-host.c | 2 +- drivers/pci/controller/dwc/pcie-designware.c | 28 +++++-------------- drivers/pci/controller/dwc/pcie-designware.h | 13 ++------- 4 files changed, 13 insertions(+), 34 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 5a158813f687..2e91222f7c98 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -212,7 +212,7 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no, __dw_pcie_ep_reset_bar(pci, func_no, bar, epf_bar->flags); - dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_INBOUND); + dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, atu_index); clear_bit(atu_index, ep->ib_window_map); ep->epf_bar[bar] = NULL; } @@ -286,7 +286,7 @@ static void dw_pcie_ep_unmap_addr(struct pci_epc *epc, u8 func_no, u8 vfunc_no, if (ret < 0) return; - dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_OUTBOUND); + dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_OB, atu_index); clear_bit(atu_index, ep->ob_window_map); } diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index b9d251b86aaf..7afd49c7da71 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -617,7 +617,7 @@ void dw_pcie_setup_rc(struct dw_pcie_rp *pp) * multiple matches */ for (i = 0; i < pci->num_ob_windows; i++) - dw_pcie_disable_atu(pci, i, DW_PCIE_REGION_OUTBOUND); + dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_OB, i); /* Get last memory resource entry */ resource_list_for_each_entry(entry, &pp->bridge->windows) { diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 330575182712..a90d3f6ce50c 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -353,7 +353,7 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, limit_addr = cpu_addr + size - 1; dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, - PCIE_ATU_REGION_OUTBOUND | index); + PCIE_ATU_REGION_DIR_OB | index); dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_BASE, lower_32_bits(cpu_addr)); dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_BASE, @@ -464,7 +464,7 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, return dw_pcie_prog_inbound_atu_unroll(pci, func_no, index, type, cpu_addr, bar); - dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | + dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_DIR_IB | index); dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, lower_32_bits(cpu_addr)); dw_pcie_writel_dbi(pci, PCIE_ATU_UPPER_TARGET, upper_32_bits(cpu_addr)); @@ -491,24 +491,10 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, return -EBUSY; } -void dw_pcie_disable_atu(struct dw_pcie *pci, int index, - enum dw_pcie_region_type type) +void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index) { - u32 region; - - switch (type) { - case DW_PCIE_REGION_INBOUND: - region = PCIE_ATU_REGION_INBOUND; - break; - case DW_PCIE_REGION_OUTBOUND: - region = PCIE_ATU_REGION_OUTBOUND; - break; - default: - return; - } - if (pci->iatu_unroll_enabled) { - if (region == PCIE_ATU_REGION_INBOUND) { + if (dir == PCIE_ATU_REGION_DIR_IB) { dw_pcie_writel_ib_unroll(pci, index, PCIE_ATU_UNR_REGION_CTRL2, ~(u32)PCIE_ATU_ENABLE); } else { @@ -516,7 +502,7 @@ void dw_pcie_disable_atu(struct dw_pcie *pci, int index, ~(u32)PCIE_ATU_ENABLE); } } else { - dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, region | index); + dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, dir | index); dw_pcie_writel_dbi(pci, PCIE_ATU_CR2, ~(u32)PCIE_ATU_ENABLE); } } @@ -661,7 +647,7 @@ static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci) max_region = dw_pcie_readl_dbi(pci, PCIE_ATU_VIEWPORT) + 1; for (i = 0; i < max_region; i++) { - dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_OUTBOUND | i); + dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_DIR_OB | i); dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000); val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET); if (val == 0x11110000) @@ -671,7 +657,7 @@ static void dw_pcie_iatu_detect_regions(struct dw_pcie *pci) } for (i = 0; i < max_region; i++) { - dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_INBOUND | i); + dw_pcie_writel_dbi(pci, PCIE_ATU_VIEWPORT, PCIE_ATU_REGION_DIR_IB | i); dw_pcie_writel_dbi(pci, PCIE_ATU_LOWER_TARGET, 0x11110000); val = dw_pcie_readl_dbi(pci, PCIE_ATU_LOWER_TARGET); if (val == 0x11110000) diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index c63ace3c3f25..72d185ff72f3 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -104,8 +104,8 @@ #define PCIE_VERSION_TYPE 0x8FC #define PCIE_ATU_VIEWPORT 0x900 -#define PCIE_ATU_REGION_INBOUND BIT(31) -#define PCIE_ATU_REGION_OUTBOUND 0 +#define PCIE_ATU_REGION_DIR_IB BIT(31) +#define PCIE_ATU_REGION_DIR_OB 0 #define PCIE_ATU_CR1 0x904 #define PCIE_ATU_INCREASE_REGION_SIZE BIT(13) #define PCIE_ATU_TYPE_MEM 0x0 @@ -185,12 +185,6 @@ struct dw_pcie; struct dw_pcie_rp; struct dw_pcie_ep; -enum dw_pcie_region_type { - DW_PCIE_REGION_UNKNOWN, - DW_PCIE_REGION_INBOUND, - DW_PCIE_REGION_OUTBOUND, -}; - enum dw_pcie_device_mode { DW_PCIE_UNKNOWN_TYPE, DW_PCIE_EP_TYPE, @@ -326,8 +320,7 @@ void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, u64 size); int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, int type, u64 cpu_addr, u8 bar); -void dw_pcie_disable_atu(struct dw_pcie *pci, int index, - enum dw_pcie_region_type type); +void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index); void dw_pcie_setup(struct dw_pcie *pci); void dw_pcie_iatu_detect(struct dw_pcie *pci); From patchwork Fri Jun 10 08:44:41 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 580847 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 B165CCCA47B for ; Fri, 10 Jun 2022 08:45:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348123AbiFJIpU (ORCPT ); Fri, 10 Jun 2022 04:45:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38414 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1348115AbiFJIpQ (ORCPT ); Fri, 10 Jun 2022 04:45:16 -0400 Received: from mail.baikalelectronics.com (mail.baikalelectronics.com [87.245.175.230]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id E15AB39826; Fri, 10 Jun 2022 01:45:11 -0700 (PDT) Received: from mail (mail.baikal.int [192.168.51.25]) by mail.baikalelectronics.com (Postfix) with ESMTP id 92C0B16B0; Fri, 10 Jun 2022 11:45:47 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.baikalelectronics.com 92C0B16B0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baikalelectronics.ru; s=mail; t=1654850747; bh=UGw/247PlFMm0LMYO2/xCJThDt+bT081ZhwJ8jW+Uag=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=GqFahJCNieuq+5+eIgu6VDi6tNoUn4S9JoA0yWx/YdfdAFpfQDZsfM3DIWEdWoIgH msNdxPEYL2zIJ0x0wIRl2nokbTxymEoLrPMJfpOFeTfjgGQSKXmpthxb45nUo1hwe4 uOXnI3SMxJl5RT8lcnk/KRnJxMBq9owm+JEwrCUA= Received: from localhost (192.168.53.207) by mail (192.168.51.25) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 10 Jun 2022 11:44:55 +0300 From: Serge Semin To: Rob Herring , Bjorn Helgaas , Lorenzo Pieralisi , Jingoo Han , Gustavo Pimentel , =?utf-8?q?Krzysztof_Wilcz?= =?utf-8?q?y=C5=84ski?= CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Frank Li , Manivannan Sadhasivam , Rob Herring , , , Subject: [PATCH v3 13/15] PCI: dwc: Verify in/out regions against iATU constraints Date: Fri, 10 Jun 2022 11:44:41 +0300 Message-ID: <20220610084444.14549-14-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20220610084444.14549-1-Sergey.Semin@baikalelectronics.ru> References: <20220610084444.14549-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Since the DWC PCIe driver private data now contains the iATU inbound and outbound regions constraints info like alignment, minimum and maximum limits, we can use them to make the in- and outbound iATU regions setup methods more strict to the ranges a callee tries to specify. That will give us the safer dw_pcie_prog_outbound_atu(), dw_pcie_prog_ep_outbound_atu() and dw_pcie_prog_inbound_atu() functions. First of all let's update the outbound ATU entries setup methods to returning the operation status. The methods will fail either in case if the range is failed to be activated or the passed region doesn't fulfill iATU constraints. Secondly the passed to the dw_pcie_prog_{ep_}outbound_atu() methods region-related parameters are verified against the detected iATU regions constraints. In particular the region limit address must not overflow the lower/upper limit CSR RW-fields otherwise the specified range will be just silently clamped. That verification will also protect the code from having u64 type overflow. Secondly let's make sure base address (CPU-address), target address (PCI-address) and size are properly aligned. Unaligned ranges will be silently aligned down (addresses) and up (limit) on writing the values to the corresponding registers, which in it turn may lead to unpredictable results like ranges virtual overlap. Finally the CPU-address alignment needs to be verified in the dw_pcie_prog_inbound_atu() method too as the DWC PCIe RC/EP registers manual demands seeing the lower bits of the in- and outbound iATU base address are always zeros. Signed-off-by: Serge Semin Reviewed-by: Rob Herring --- Changelog v3: - Drop outbound iATU window size alignment constraint. (@Manivannan) --- drivers/pci/controller/dwc/pcie-designware.c | 38 +++++++++++++------- drivers/pci/controller/dwc/pcie-designware.h | 10 +++--- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 776752891d11..9c622b635fdd 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -8,6 +8,7 @@ * Author: Jingoo Han */ +#include #include #include #include @@ -308,9 +309,9 @@ static inline u32 dw_pcie_enable_ecrc(u32 val) return val | PCIE_ATU_TD; } -static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, - int index, int type, u64 cpu_addr, - u64 pci_addr, u64 size) +static int __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, + int index, int type, u64 cpu_addr, + u64 pci_addr, u64 size) { u32 retries, val; u64 limit_addr; @@ -320,6 +321,12 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, limit_addr = cpu_addr + size - 1; + if ((limit_addr & ~pci->region_limit) != (cpu_addr & ~pci->region_limit) || + !IS_ALIGNED(cpu_addr, pci->region_align) || + !IS_ALIGNED(pci_addr, pci->region_align) || !size) { + return -EINVAL; + } + dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LOWER_BASE, lower_32_bits(cpu_addr)); dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_BASE, @@ -353,27 +360,29 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { val = dw_pcie_readl_atu_ob(pci, index, PCIE_ATU_REGION_CTRL2); if (val & PCIE_ATU_ENABLE) - return; + return 0; mdelay(LINK_WAIT_IATU); } dev_err(pci->dev, "Outbound iATU is not being enabled\n"); + + return -ETIMEDOUT; } -void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, - u64 cpu_addr, u64 pci_addr, u64 size) +int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, + u64 cpu_addr, u64 pci_addr, u64 size) { - __dw_pcie_prog_outbound_atu(pci, 0, index, type, - cpu_addr, pci_addr, size); + return __dw_pcie_prog_outbound_atu(pci, 0, index, type, + cpu_addr, pci_addr, size); } -void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, - int type, u64 cpu_addr, u64 pci_addr, - u64 size) +int dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, + int type, u64 cpu_addr, u64 pci_addr, + u64 size) { - __dw_pcie_prog_outbound_atu(pci, func_no, index, type, - cpu_addr, pci_addr, size); + return __dw_pcie_prog_outbound_atu(pci, func_no, index, type, + cpu_addr, pci_addr, size); } static inline u32 dw_pcie_readl_atu_ib(struct dw_pcie *pci, u32 index, u32 reg) @@ -392,6 +401,9 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, { u32 retries, val; + if (!IS_ALIGNED(cpu_addr, pci->region_align)) + return -EINVAL; + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET, lower_32_bits(cpu_addr)); dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET, diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 25c86771c810..60f1ddc54933 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -304,12 +304,10 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val); int dw_pcie_link_up(struct dw_pcie *pci); void dw_pcie_upconfig_setup(struct dw_pcie *pci); int dw_pcie_wait_for_link(struct dw_pcie *pci); -void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, - int type, u64 cpu_addr, u64 pci_addr, - u64 size); -void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, - int type, u64 cpu_addr, u64 pci_addr, - u64 size); +int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, + u64 cpu_addr, u64 pci_addr, u64 size); +int dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, + int type, u64 cpu_addr, u64 pci_addr, u64 size); int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, int type, u64 cpu_addr, u8 bar); void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index); From patchwork Fri Jun 10 08:44:42 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 580834 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 4DAD7CCA482 for ; Fri, 10 Jun 2022 09:12:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348469AbiFJJMU (ORCPT ); Fri, 10 Jun 2022 05:12:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41892 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244940AbiFJJL7 (ORCPT ); Fri, 10 Jun 2022 05:11:59 -0400 Received: from mail.baikalelectronics.com (mail.baikalelectronics.com [87.245.175.230]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 3AF1827B987; Fri, 10 Jun 2022 02:09:49 -0700 (PDT) Received: from mail (mail.baikal.int [192.168.51.25]) by mail.baikalelectronics.com (Postfix) with ESMTP id 8899C16C0; Fri, 10 Jun 2022 11:45:48 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.baikalelectronics.com 8899C16C0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baikalelectronics.ru; s=mail; t=1654850748; bh=sWm2wkwgYyFQa6x4pRX1K7dze5ryKklI+g5phTVa8zQ=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=MKyPMr2orJRDLj8worVk5PBavw35V0yYoX2fMl4qv4Ul4bg3vQx2VqSxlRjkfoF5/ usV7hz/J/6RENEKxIfKRS8cOt5xB84m98YpaZ6upyRcOp/oGRiH2SeqbnaQZhgbmHt 9B/sQesv+lUWaEJnCMpmkDeAyf+//Jin9GkAOtg4= Received: from localhost (192.168.53.207) by mail (192.168.51.25) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 10 Jun 2022 11:44:56 +0300 From: Serge Semin To: Rob Herring , Bjorn Helgaas , Lorenzo Pieralisi , Jingoo Han , Gustavo Pimentel , =?utf-8?q?Krzysztof_Wilcz?= =?utf-8?q?y=C5=84ski?= , Rahul Tanwar CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Frank Li , Manivannan Sadhasivam , Rob Herring , , , Subject: [PATCH v3 14/15] PCI: dwc: Check iATU in/outbound ranges setup methods status Date: Fri, 10 Jun 2022 11:44:42 +0300 Message-ID: <20220610084444.14549-15-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20220610084444.14549-1-Sergey.Semin@baikalelectronics.ru> References: <20220610084444.14549-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org Let's make the DWC PCIe RC/EP safer and more verbose for the invalid or failed inbound and outbound iATU windows setups. Needless to say that silently ignoring iATU regions setup errors may cause unpredictable errors. For instance if for some reason a cfg or IO window fails to be activated, then any CFG/IO requested won't reach target PCIe devices and the corresponding accessors will return platform-specific random values. First of all we need to convert dw_pcie_ep_outbound_atu() method to check whether the specified outbound iATU range is successfully setup. That method is called by the pci_epc_ops.map_addr callback. Thus we'll make the EP-specific CPU->PCIe memory mappings saver. Secondly since the iATU outbound range programming method now returns the operation status, it will be handy to take that status into account in the pci_ops.{map_bus,read,write} methods. Thus any failed mapping will be immediately noticeable by the PCIe CFG operations requesters. Finally we need to convert the dw_pcie_setup_rc() method to returning the operation status, since the iATU outbound ranges setup procedure may now fail. It will be especially handy in case if the DW PCIe RC DT-node has invalid/unsupported (dma-)ranges property. Note since the suggested modification causes having too wide code indentation, it is reasonable from maintainability and readability points of view to move the outbound ranges setup procedure in the separate function. Signed-off-by: Serge Semin Reviewed-by: Rob Herring --- .../pci/controller/dwc/pcie-designware-ep.c | 9 +- .../pci/controller/dwc/pcie-designware-host.c | 153 ++++++++++++------ drivers/pci/controller/dwc/pcie-designware.h | 5 +- drivers/pci/controller/dwc/pcie-intel-gw.c | 6 +- 4 files changed, 114 insertions(+), 59 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 2e91222f7c98..627c4b69878c 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -184,8 +184,9 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, u8 func_no, phys_addr_t phys_addr, u64 pci_addr, size_t size) { - u32 free_win; struct dw_pcie *pci = to_dw_pcie_from_ep(ep); + u32 free_win; + int ret; free_win = find_first_zero_bit(ep->ob_window_map, pci->num_ob_windows); if (free_win >= pci->num_ob_windows) { @@ -193,8 +194,10 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, u8 func_no, return -EINVAL; } - dw_pcie_prog_ep_outbound_atu(pci, func_no, free_win, PCIE_ATU_TYPE_MEM, - phys_addr, pci_addr, size); + ret = dw_pcie_prog_ep_outbound_atu(pci, func_no, free_win, PCIE_ATU_TYPE_MEM, + phys_addr, pci_addr, size); + if (ret) + return ret; set_bit(free_win, ep->ob_window_map); ep->outbound_addr[free_win] = phys_addr; diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 7afd49c7da71..b52f7f4db191 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -411,7 +411,9 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) dw_pcie_iatu_detect(pci); - dw_pcie_setup_rc(pp); + ret = dw_pcie_setup_rc(pp); + if (ret) + goto err_free_msi; if (!dw_pcie_link_up(pci)) { ret = dw_pcie_start_link(pci); @@ -465,10 +467,10 @@ EXPORT_SYMBOL_GPL(dw_pcie_host_deinit); static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus, unsigned int devfn, int where) { - int type; - u32 busdev; struct dw_pcie_rp *pp = bus->sysdata; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + int type, ret; + u32 busdev; /* * Checking whether the link is up here is a last line of defense @@ -489,8 +491,10 @@ static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus, else type = PCIE_ATU_TYPE_CFG1; - - dw_pcie_prog_outbound_atu(pci, 0, type, pp->cfg0_base, busdev, pp->cfg0_size); + ret = dw_pcie_prog_outbound_atu(pci, 0, type, pp->cfg0_base, busdev, + pp->cfg0_size); + if (ret) + return NULL; return pp->va_cfg0_base + where; } @@ -498,33 +502,45 @@ static void __iomem *dw_pcie_other_conf_map_bus(struct pci_bus *bus, static int dw_pcie_rd_other_conf(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { - int ret; struct dw_pcie_rp *pp = bus->sysdata; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + int ret; ret = pci_generic_config_read(bus, devfn, where, size, val); + if (ret != PCIBIOS_SUCCESSFUL) + return ret; - if (!ret && pp->cfg0_io_shared) - dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base, - pp->io_bus_addr, pp->io_size); + if (pp->cfg0_io_shared) { + ret = dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, + pp->io_base, pp->io_bus_addr, + pp->io_size); + if (ret) + return PCIBIOS_SET_FAILED; + } - return ret; + return PCIBIOS_SUCCESSFUL; } static int dw_pcie_wr_other_conf(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val) { - int ret; struct dw_pcie_rp *pp = bus->sysdata; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + int ret; ret = pci_generic_config_write(bus, devfn, where, size, val); + if (ret != PCIBIOS_SUCCESSFUL) + return ret; - if (!ret && pp->cfg0_io_shared) - dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, pp->io_base, - pp->io_bus_addr, pp->io_size); + if (pp->cfg0_io_shared) { + ret = dw_pcie_prog_outbound_atu(pci, 0, PCIE_ATU_TYPE_IO, + pp->io_base, pp->io_bus_addr, + pp->io_size); + if (ret) + return PCIBIOS_SET_FAILED; + } - return ret; + return PCIBIOS_SUCCESSFUL; } static struct pci_ops dw_child_pcie_ops = { @@ -551,10 +567,72 @@ static struct pci_ops dw_pcie_ops = { .write = pci_generic_config_write, }; -void dw_pcie_setup_rc(struct dw_pcie_rp *pp) +static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp) +{ + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct resource_entry *entry; + int i, ret; + + /* Note the very first outbound ATU is used for CFG IOs */ + if (!pci->num_ob_windows) { + dev_err(pci->dev, "No outbound iATU found\n"); + return -EINVAL; + } + + /* + * Ensure all outbound windows are disabled before proceeding with + * the MEM/IO ranges setups. + */ + for (i = 0; i < pci->num_ob_windows; i++) + dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_OB, i); + + i = 0; + resource_list_for_each_entry(entry, &pp->bridge->windows) { + if (resource_type(entry->res) != IORESOURCE_MEM) + continue; + + if (pci->num_ob_windows <= ++i) + break; + + ret = dw_pcie_prog_outbound_atu(pci, i, PCIE_ATU_TYPE_MEM, + entry->res->start, + entry->res->start - entry->offset, + resource_size(entry->res)); + if (ret) { + dev_err(pci->dev, "Failed to set MEM range %pr\n", + entry->res); + return ret; + } + } + + if (pp->io_size) { + if (pci->num_ob_windows > ++i) { + ret = dw_pcie_prog_outbound_atu(pci, i, PCIE_ATU_TYPE_IO, + pp->io_base, + pp->io_bus_addr, + pp->io_size); + if (ret) { + dev_err(pci->dev, "Failed to set IO range %pr\n", + entry->res); + return ret; + } + } else { + pp->cfg0_io_shared = true; + } + } + + if (pci->num_ob_windows <= i) + dev_warn(pci->dev, "Resources exceed number of ATU entries (%d)\n", + pci->num_ob_windows); + + return 0; +} + +int dw_pcie_setup_rc(struct dw_pcie_rp *pp) { - u32 val, ctrl, num_ctrls; struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + u32 val, ctrl, num_ctrls; + int ret; /* * Enable DBI read-only registers for writing/updating configuration. @@ -609,42 +687,9 @@ void dw_pcie_setup_rc(struct dw_pcie_rp *pp) * ATU, so we should not program the ATU here. */ if (pp->bridge->child_ops == &dw_child_pcie_ops) { - int i, atu_idx = 0; - struct resource_entry *entry; - - /* - * Ensure all outbound windows are disabled so there are - * multiple matches - */ - for (i = 0; i < pci->num_ob_windows; i++) - dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_OB, i); - - /* Get last memory resource entry */ - resource_list_for_each_entry(entry, &pp->bridge->windows) { - if (resource_type(entry->res) != IORESOURCE_MEM) - continue; - - if (pci->num_ob_windows <= ++atu_idx) - break; - - dw_pcie_prog_outbound_atu(pci, atu_idx, - PCIE_ATU_TYPE_MEM, entry->res->start, - entry->res->start - entry->offset, - resource_size(entry->res)); - } - - if (pp->io_size) { - if (pci->num_ob_windows > ++atu_idx) - dw_pcie_prog_outbound_atu(pci, atu_idx, - PCIE_ATU_TYPE_IO, pp->io_base, - pp->io_bus_addr, pp->io_size); - else - pp->cfg0_io_shared = true; - } - - if (pci->num_ob_windows <= atu_idx) - dev_warn(dev, "Resources exceed number of ATU entries (%d)\n", - pci->num_ob_windows); + ret = dw_pcie_iatu_setup(pp); + if (ret) + return ret; } dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0); @@ -657,5 +702,7 @@ void dw_pcie_setup_rc(struct dw_pcie_rp *pp) dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val); dw_pcie_dbi_ro_wr_dis(pci); + + return 0; } EXPORT_SYMBOL_GPL(dw_pcie_setup_rc); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 60f1ddc54933..c3e73ed9aff5 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -387,7 +387,7 @@ static inline void dw_pcie_stop_link(struct dw_pcie *pci) #ifdef CONFIG_PCIE_DW_HOST irqreturn_t dw_handle_msi_irq(struct dw_pcie_rp *pp); -void dw_pcie_setup_rc(struct dw_pcie_rp *pp); +int dw_pcie_setup_rc(struct dw_pcie_rp *pp); int dw_pcie_host_init(struct dw_pcie_rp *pp); void dw_pcie_host_deinit(struct dw_pcie_rp *pp); int dw_pcie_allocate_domains(struct dw_pcie_rp *pp); @@ -399,8 +399,9 @@ static inline irqreturn_t dw_handle_msi_irq(struct dw_pcie_rp *pp) return IRQ_NONE; } -static inline void dw_pcie_setup_rc(struct dw_pcie_rp *pp) +static inline int dw_pcie_setup_rc(struct dw_pcie_rp *pp) { + return 0; } static inline int dw_pcie_host_init(struct dw_pcie_rp *pp) diff --git a/drivers/pci/controller/dwc/pcie-intel-gw.c b/drivers/pci/controller/dwc/pcie-intel-gw.c index a44f685ec94d..c3481200e86a 100644 --- a/drivers/pci/controller/dwc/pcie-intel-gw.c +++ b/drivers/pci/controller/dwc/pcie-intel-gw.c @@ -302,7 +302,11 @@ static int intel_pcie_host_setup(struct intel_pcie *pcie) intel_pcie_ltssm_disable(pcie); intel_pcie_link_setup(pcie); intel_pcie_init_n_fts(pci); - dw_pcie_setup_rc(&pci->pp); + + ret = dw_pcie_setup_rc(&pci->pp); + if (ret) + goto app_init_err; + dw_pcie_upconfig_setup(pci); intel_pcie_device_rst_deassert(pcie); From patchwork Fri Jun 10 08:44:43 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Serge Semin X-Patchwork-Id: 580835 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 6C02CC43334 for ; Fri, 10 Jun 2022 09:12:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1348414AbiFJJMT (ORCPT ); Fri, 10 Jun 2022 05:12:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48024 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344194AbiFJJMA (ORCPT ); Fri, 10 Jun 2022 05:12:00 -0400 Received: from mail.baikalelectronics.com (mail.baikalelectronics.com [87.245.175.230]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 3AF91285AAC; Fri, 10 Jun 2022 02:09:49 -0700 (PDT) Received: from mail (mail.baikal.int [192.168.51.25]) by mail.baikalelectronics.com (Postfix) with ESMTP id 8086416A4; Fri, 10 Jun 2022 11:45:50 +0300 (MSK) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.baikalelectronics.com 8086416A4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baikalelectronics.ru; s=mail; t=1654850750; bh=EDILp+MFSSPr1gFjUysXLOPNDUyEdUcN69hK1tuUiXU=; h=From:To:CC:Subject:Date:In-Reply-To:References:From; b=hMCXPZR0QoLoqdR9D145oHXPCIZszi18d+1KkOTaveudEfhPGKeGC0qa7YPALusMz ipH8bO8kLkCwP2VQIUumsVRWWn/sFc09bx8yCbCGc6LKaqwboWsTLBFy9LYGBgvGcV ARi2VGRT7yKb46D8ywYBfjOhFLkCmyGbpxC58PL0= Received: from localhost (192.168.53.207) by mail (192.168.51.25) with Microsoft SMTP Server (TLS) id 15.0.1395.4; Fri, 10 Jun 2022 11:44:57 +0300 From: Serge Semin To: Rob Herring , Bjorn Helgaas , Lorenzo Pieralisi , Jingoo Han , Gustavo Pimentel , =?utf-8?q?Krzysztof_Wilcz?= =?utf-8?q?y=C5=84ski?= CC: Serge Semin , Serge Semin , Alexey Malahov , Pavel Parkhomenko , Frank Li , Manivannan Sadhasivam , Rob Herring , , , Subject: [PATCH v3 15/15] PCI: dwc: Introduce dma-ranges property support for RC-host Date: Fri, 10 Jun 2022 11:44:43 +0300 Message-ID: <20220610084444.14549-16-Sergey.Semin@baikalelectronics.ru> In-Reply-To: <20220610084444.14549-1-Sergey.Semin@baikalelectronics.ru> References: <20220610084444.14549-1-Sergey.Semin@baikalelectronics.ru> MIME-Version: 1.0 X-ClientProxiedBy: MAIL.baikal.int (192.168.51.25) To mail (192.168.51.25) Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org In accordance with the generic PCIe Root Port DT-bindings the "dma-ranges" property has the same format as the "ranges" property. The only difference is in their semantics. The "dma-ranges" property describes the PCIe-to-CPU memory mapping in opposite to the CPU-to-PCIe mapping of the "ranges" property. Even though the DW PCIe controllers are normally equipped with the internal Address Translation Unit which inbound and outbound tables can be used to implement both properties semantics, it was surprising for me to discover that the host-related part of the DW PCIe driver currently supports the "ranges" property only while the "dma-ranges" windows are just ignored. Having the "dma-ranges" supported in the driver would be very handy for the platforms, that don't tolerate the 1:1 CPU-PCIe memory mapping and require a customized PCIe memory layout. So let's fix that by introducing the "dma-ranges" property support. First of all we suggest to rename the dw_pcie_prog_inbound_atu() method to dw_pcie_prog_ep_inbound_atu() and create a new version of the dw_pcie_prog_inbound_atu() function. Thus we'll have two methods for the RC and EP controllers respectively in the same way as it has been developed for the outbound ATU setup methods. Secondly aside with the memory window index and type the new dw_pcie_prog_inbound_atu() function will accept CPU address, PCIe address and size as its arguments. These parameters define the PCIe and CPU memory ranges which will be used to setup the respective inbound ATU mapping. The passed parameters need to be verified against the ATU ranges constraints in the same way as it is done for the outbound ranges. Finally the DMA-ranges detected for the PCIe controller need to be converted to the inbound ATU entries during the host controller initialization procedure. It will be done in the framework of the dw_pcie_iatu_setup() method. Note before setting the inbound ranges up we need to disable all the inbound ATU entries in order to prevent unexpected PCIe TLPs translations defined by some third party software like bootloaders. Signed-off-by: Serge Semin Reviewed-by: Rob Herring --- Changelog v3: - Drop inbound iATU window size alignment constraint. (@Manivannan) --- .../pci/controller/dwc/pcie-designware-ep.c | 4 +- .../pci/controller/dwc/pcie-designware-host.c | 32 ++++++++++- drivers/pci/controller/dwc/pcie-designware.c | 56 ++++++++++++++++++- drivers/pci/controller/dwc/pcie-designware.h | 6 +- 4 files changed, 89 insertions(+), 9 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 627c4b69878c..441feff1917a 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -167,8 +167,8 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, int type, return -EINVAL; } - ret = dw_pcie_prog_inbound_atu(pci, func_no, free_win, type, - cpu_addr, bar); + ret = dw_pcie_prog_ep_inbound_atu(pci, func_no, free_win, type, + cpu_addr, bar); if (ret < 0) { dev_err(pci->dev, "Failed to program IB window\n"); return ret; diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index b52f7f4db191..56a678abe828 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -580,12 +580,15 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp) } /* - * Ensure all outbound windows are disabled before proceeding with - * the MEM/IO ranges setups. + * Ensure all out/inbound windows are disabled before proceeding with + * the MEM/IO (dma-)ranges setups. */ for (i = 0; i < pci->num_ob_windows; i++) dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_OB, i); + for (i = 0; i < pci->num_ib_windows; i++) + dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, i); + i = 0; resource_list_for_each_entry(entry, &pp->bridge->windows) { if (resource_type(entry->res) != IORESOURCE_MEM) @@ -622,9 +625,32 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp) } if (pci->num_ob_windows <= i) - dev_warn(pci->dev, "Resources exceed number of ATU entries (%d)\n", + dev_warn(pci->dev, "Ranges exceed outbound iATU size (%d)\n", pci->num_ob_windows); + i = 0; + resource_list_for_each_entry(entry, &pp->bridge->dma_ranges) { + if (resource_type(entry->res) != IORESOURCE_MEM) + continue; + + if (pci->num_ib_windows <= i) + break; + + ret = dw_pcie_prog_inbound_atu(pci, i++, PCIE_ATU_TYPE_MEM, + entry->res->start, + entry->res->start - entry->offset, + resource_size(entry->res)); + if (ret) { + dev_err(pci->dev, "Failed to set DMA range %pr\n", + entry->res); + return ret; + } + } + + if (pci->num_ib_windows <= i) + dev_warn(pci->dev, "Dma-ranges exceed inbound iATU size (%u)\n", + pci->num_ib_windows); + return 0; } diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 9c622b635fdd..7a5be3c4f8e0 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -396,8 +396,60 @@ static inline void dw_pcie_writel_atu_ib(struct dw_pcie *pci, u32 index, u32 reg dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_IB, index, reg, val); } -int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, - int type, u64 cpu_addr, u8 bar) +int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type, + u64 cpu_addr, u64 pci_addr, u64 size) +{ + u64 limit_addr = pci_addr + size - 1; + u32 retries, val; + + if ((limit_addr & ~pci->region_limit) != (pci_addr & ~pci->region_limit) || + !IS_ALIGNED(cpu_addr, pci->region_align) || + !IS_ALIGNED(pci_addr, pci->region_align) || !size) { + return -EINVAL; + } + + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_BASE, + lower_32_bits(pci_addr)); + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_BASE, + upper_32_bits(pci_addr)); + + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LIMIT, + lower_32_bits(limit_addr)); + if (dw_pcie_ver_is_ge(pci, 460A)) + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_LIMIT, + upper_32_bits(limit_addr)); + + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET, + lower_32_bits(cpu_addr)); + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET, + upper_32_bits(cpu_addr)); + + val = type; + if (upper_32_bits(limit_addr) > upper_32_bits(pci_addr) && + dw_pcie_ver_is_ge(pci, 460A)) + val |= PCIE_ATU_INCREASE_REGION_SIZE; + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL1, val); + dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2, PCIE_ATU_ENABLE); + + /* + * Make sure ATU enable takes effect before any subsequent config + * and I/O accesses. + */ + for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { + val = dw_pcie_readl_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2); + if (val & PCIE_ATU_ENABLE) + return 0; + + mdelay(LINK_WAIT_IATU); + } + + dev_err(pci->dev, "Inbound iATU is not being enabled\n"); + + return -ETIMEDOUT; +} + +int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, + int type, u64 cpu_addr, u8 bar) { u32 retries, val; diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index c3e73ed9aff5..5954e8cf9eec 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -308,8 +308,10 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, u64 cpu_addr, u64 pci_addr, u64 size); int dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, int type, u64 cpu_addr, u64 pci_addr, u64 size); -int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, - int type, u64 cpu_addr, u8 bar); +int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type, + u64 cpu_addr, u64 pci_addr, u64 size); +int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, + int type, u64 cpu_addr, u8 bar); void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index); void dw_pcie_setup(struct dw_pcie *pci); void dw_pcie_iatu_detect(struct dw_pcie *pci);