>From b35d92c71d40d3f6471900372f73e07079f8ee34 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Chundru 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 Signed-off-by: Manivannan Sadhasivam --- .../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