[PATCH] PCI: qcom: Enable iATU mapping for memory & IO regions
From: Krishna Chaitanya Chundru
Date: Fri Nov 28 2025 - 06:14:17 EST
Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@xxxxxxxxxxxxxxxx>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@xxxxxxxxxxxxxxxx>
---
.../pci/controller/dwc/pcie-designware-host.c | 37 +++++++++++--------
drivers/pci/controller/dwc/pcie-designware.c | 3 ++
drivers/pci/controller/dwc/pcie-designware.h | 2 +-
3 files changed, 26 insertions(+), 16 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index e92513c5bda5..cffd66d51d02 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,
@@ -433,7 +434,7 @@ static int dw_pcie_config_ecam_iatu(struct dw_pcie_rp *pp)
* 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) */
@@ -448,14 +449,20 @@ static int dw_pcie_config_ecam_iatu(struct dw_pcie_rp *pp)
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)
@@ -630,14 +637,6 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
if (ret)
goto err_free_msi;
- if (pp->ecam_enabled) {
- ret = dw_pcie_config_ecam_iatu(pp);
- if (ret) {
- dev_err(dev, "Failed to configure iATU in ECAM mode\n");
- goto err_free_msi;
- }
- }
-
/*
* Allocate the resource for MSG TLP before programming the iATU
* outbound window in dw_pcie_setup_rc(). Since the allocation depends
@@ -942,7 +941,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) {
@@ -1086,12 +1085,20 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
* the platform uses its own address translation component rather than
* ATU, so we should not program the ATU here.
*/
- if (pp->bridge->child_ops == &dw_child_pcie_ops) {
+ if (pp->bridge->child_ops == &dw_child_pcie_ops || pp->ecam_enabled) {
ret = dw_pcie_iatu_setup(pp);
if (ret)
return ret;
}
+ if (pp->ecam_enabled) {
+ ret = dw_pcie_config_ecam_iatu(pp);
+ if (ret) {
+ dev_err(pci->dev, "Failed to configure iATU in ECAM mode\n");
+ return ret;
+ }
+ }
+
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
/* Program correct class for RC */
@@ -1113,7 +1120,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 +1130,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.48.1
--4taha6h4y7ppae6c--