[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