[PATCH v9 4/4] PCI: dwc: Support ECAM mechanism by enabling iATU 'CFG Shift Feature'

Krishna Chaitanya Chundru krishna.chundru at oss.qualcomm.com
Fri Nov 28 05:44:54 PST 2025



On 11/28/2025 2:07 PM, Maciej W. Rozycki wrote:
> On Fri, 28 Nov 2025, Krishna Chaitanya Chundru wrote:
>
>>>> Designware databook r5.20a, sec 3.10.10.3 documents the 'CFG Shift
>>>> Feature'
>>>> of the internal Address Translation Unit (iATU). When this feature is
>>>> enabled, it shifts/maps the BDF contained in the bits [27:12] of the
>>>> target
>>>> address in MEM TLP to become BDF of the CFG TLP. This essentially
>>>> implements the Enhanced Configuration Address Mapping (ECAM) mechanism as
>>>> defined in PCIe r6.0, sec 7.2.2.
>>>    So this broke a parallel port on my HiFive Unmatched machine (a SiFive
>>> FU740-C000 based system), the driver no longer registers the device, no
>>> /dev/parport0 anymore.
>> Hi Maciej, can you share us lspci -vvv o/p with working & non working case and
>> also can you point us parport driver. - Krishna Chaitanya.
>   I'm not sure what you mean as to the parport driver; it's standard stuff:
>
> $ zgrep PARPORT /proc/config.gz
> CONFIG_PARPORT=y
> CONFIG_PARPORT_PC=y
> # CONFIG_PARPORT_SERIAL is not set
> CONFIG_PARPORT_PC_FIFO=y
> CONFIG_PARPORT_1284=y
> # CONFIG_PATA_PARPORT is not set
> # CONFIG_I2C_PARPORT is not set
> # CONFIG_USB_SERIAL_MOS7715_PARPORT is not set
> $
>
> I've attached output from `lspci -xxxx' so that you can decode it yourself
> however you need, though I fail to see anything standing out there.
>
>   If you can't figure out what's going on here, then I'll try to poke at
> the driver to see what exactly it is that causes it to fail there, but I'm
> a little constrained on the resources and completely unfamiliar with the
> ECAM feature (and the lack of documentation for the DW IP does not help).
>
>   I have no slightest idea why it should cause a regression such as this,
> it seems totally unrelated.  Yet it's 100% reproducible.  Could this be
> because it's the only device in the system that actually uses PCI/e port
> I/O?
Hi Maciej, Can you try attached patch and let me know if that is helping 
you or not. - Krishna Chaitanya.
> # cat /proc/ioports
> 00000000-0000ffff : pcie at e00000000
>    00001000-00002fff : PCI Bus 0000:01
>      00001000-00002fff : PCI Bus 0000:02
>        00001000-00002fff : PCI Bus 0000:05
>          00001000-00002fff : PCI Bus 0000:06
>            00001000-00001fff : PCI Bus 0000:07
>            00001000-00001007 : 0000:07:00.0
>            00001000-00001002 : parport0
>            00001003-00001007 : parport0
>            00001008-0000100b : 0000:07:00.0
>            00001008-0000100a : parport0
>            00002000-00002fff : PCI Bus 0000:08
>            00002000-00002fff : PCI Bus 0000:09
>            00002000-000020ff : 0000:09:01.0
>            00002100-0000217f : 0000:09:02.0
> #
>
> (Hmm, indentation does not appear correct to me for buses below 0000:07.)
>
>    Maciej
-------------- next part --------------
From ad002661c2e559ee3ec523b00e23948407968cd7 Mon Sep 17 00:00:00 2001
From: Krishna Chaitanya Chundru <krishna.chundru at oss.qualcomm.com>
Date: Fri, 28 Nov 2025 16:44:17 +0530
Subject: [PATCH] PCI: qcom: Enable iATU mapping for memory & IO regions

Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru at oss.qualcomm.com>
---
 .../pci/controller/dwc/pcie-designware-host.c | 24 ++++++++++++++-----
 drivers/pci/controller/dwc/pcie-designware.c  |  3 +++
 drivers/pci/controller/dwc/pcie-designware.h  |  2 +-
 3 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index e92513c5bda5..a60f1539fadc 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -36,6 +36,7 @@ static struct pci_ops dw_child_pcie_ops;
 
 #define IS_256MB_ALIGNED(x) IS_ALIGNED(x, SZ_256M)
 
+static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp);
 static const struct msi_parent_ops dw_pcie_msi_parent_ops = {
 	.required_flags		= DW_PCIE_MSI_FLAGS_REQUIRED,
 	.supported_flags	= DW_PCIE_MSI_FLAGS_SUPPORTED,
@@ -427,13 +428,17 @@ static int dw_pcie_config_ecam_iatu(struct dw_pcie_rp *pp)
 
 	bus = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS);
 
+	ret = dw_pcie_iatu_setup(pp);
+	if (ret)
+		return ret;
+
 	/*
 	 * Root bus under the host bridge doesn't require any iATU configuration
 	 * as DBI region will be used to access root bus config space.
 	 * Immediate bus under Root Bus, needs type 0 iATU configuration and
 	 * remaining buses need type 1 iATU configuration.
 	 */
-	atu.index = 0;
+	atu.index = pp->ob_atu_index;
 	atu.type = PCIE_ATU_TYPE_CFG0;
 	atu.parent_bus_addr = pp->cfg0_base + SZ_1M;
 	/* 1MiB is to cover 1 (bus) * 32 (devices) * 8 (functions) */
@@ -443,19 +448,26 @@ static int dw_pcie_config_ecam_iatu(struct dw_pcie_rp *pp)
 	if (ret)
 		return ret;
 
+
 	bus_range_max = resource_size(bus->res);
 
 	if (bus_range_max < 2)
 		return 0;
 
+	pp->ob_atu_index++;
+
 	/* Configure remaining buses in type 1 iATU configuration */
-	atu.index = 1;
+	atu.index = pp->ob_atu_index;
 	atu.type = PCIE_ATU_TYPE_CFG1;
 	atu.parent_bus_addr = pp->cfg0_base + SZ_2M;
 	atu.size = (SZ_1M * bus_range_max) - SZ_2M;
 	atu.ctrl2 = PCIE_ATU_CFG_SHIFT_MODE_ENABLE;
 
-	return dw_pcie_prog_outbound_atu(pci, &atu);
+	ret = dw_pcie_prog_outbound_atu(pci, &atu);
+	if (!ret)
+		pp->ob_atu_index++;
+
+	return ret;
 }
 
 static int dw_pcie_create_ecam_window(struct dw_pcie_rp *pp, struct resource *res)
@@ -942,7 +954,7 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
 		dev_warn(pci->dev, "Ranges exceed outbound iATU size (%d)\n",
 			 pci->num_ob_windows);
 
-	pp->msg_atu_index = i;
+	pp->ob_atu_index = i;
 
 	i = 0;
 	resource_list_for_each_entry(entry, &pp->bridge->dma_ranges) {
@@ -1113,7 +1125,7 @@ static int dw_pcie_pme_turn_off(struct dw_pcie *pci)
 	void __iomem *mem;
 	int ret;
 
-	if (pci->num_ob_windows <= pci->pp.msg_atu_index)
+	if (pci->num_ob_windows <= pci->pp.ob_atu_index)
 		return -ENOSPC;
 
 	if (!pci->pp.msg_res)
@@ -1123,7 +1135,7 @@ static int dw_pcie_pme_turn_off(struct dw_pcie *pci)
 	atu.routing = PCIE_MSG_TYPE_R_BC;
 	atu.type = PCIE_ATU_TYPE_MSG;
 	atu.size = resource_size(pci->pp.msg_res);
-	atu.index = pci->pp.msg_atu_index;
+	atu.index = pci->pp.ob_atu_index;
 
 	atu.parent_bus_addr = pci->pp.msg_res->start - pci->parent_bus_offset;
 
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index c644216995f6..d27b469b417b 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -478,6 +478,9 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci,
 
 	limit_addr = parent_bus_addr + atu->size - 1;
 
+	if (atu->index > pci->num_ob_windows)
+		return -ENOSPC;
+
 	if ((limit_addr & ~pci->region_limit) != (parent_bus_addr & ~pci->region_limit) ||
 	    !IS_ALIGNED(parent_bus_addr, pci->region_align) ||
 	    !IS_ALIGNED(atu->pci_addr, pci->region_align) || !atu->size) {
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index e995f692a1ec..69d0bd8b3c57 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -423,8 +423,8 @@ struct dw_pcie_rp {
 	struct pci_host_bridge  *bridge;
 	raw_spinlock_t		lock;
 	DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
+	int			ob_atu_index;
 	bool			use_atu_msg;
-	int			msg_atu_index;
 	struct resource		*msg_res;
 	bool			use_linkup_irq;
 	struct pci_eq_presets	presets;
-- 
2.34.1



More information about the linux-arm-kernel mailing list