Skip to content

Commit 43d324e

Browse files
PCI: dwc: Fix missing iATU setup when ECAM is enabled
When ECAM is enabled, the driver skipped calling dw_pcie_iatu_setup() before configuring ECAM iATU entries. This left IO and MEM outbound windows unprogrammed, resulting in broken IO transactions. Additionally, dw_pcie_config_ecam_iatu() was only called during host initialization, so ECAM-related iATU entries were not restored after suspend/resume, leading to failures in configuration space access To resolve these issues, move the ECAM iATU configuration to dw_pcie_iatu_setup(), and invoke dw_pcie_iatu_setup() when ECAM is enabled. Furthermore, add error checks in dw_pcie_prog_outbound_atu() and dw_pcie_prog_inbound_atu() such that an error is returned if the caller is trying to program an iATU that is outside the number of iATUs supported by the controller. Fixes: f6fd357 ("PCI: dwc: Prepare the driver for enabling ECAM mechanism using iATU 'CFG Shift Feature'") Reported-by: Maciej W. Rozycki <macro@orcam.me.uk> Closes: https://lore.kernel.org/all/alpine.DEB.2.21.2511280256260.36486@angie.orcam.me.uk/ Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com> Co-developed-by: Niklas Cassel <cassel@kernel.org> Signed-off-by: Niklas Cassel <cassel@kernel.org> [mani: used imperative tone] Signed-off-by: Manivannan Sadhasivam <mani@kernel.org> Tested-by: Maciej W. Rozycki <macro@orcam.me.uk> Reviewed-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Hans Zhang <zhanghuabing@ecosda.com> Reviewed-by: Frank Li <Frank.Li@nxp.com> Cc: stable+noautosel@kernel.org # depends on Clean up iATU index usage in dw_pcie_iatu_setup() Link: https://patch.msgid.link/20260127151038.1484881-8-cassel@kernel.org
1 parent b5dab9b commit 43d324e

2 files changed

Lines changed: 28 additions & 11 deletions

File tree

drivers/pci/controller/dwc/pcie-designware-host.c

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -641,14 +641,6 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
641641
if (ret)
642642
goto err_free_msi;
643643

644-
if (pp->ecam_enabled) {
645-
ret = dw_pcie_config_ecam_iatu(pp);
646-
if (ret) {
647-
dev_err(dev, "Failed to configure iATU in ECAM mode\n");
648-
goto err_free_msi;
649-
}
650-
}
651-
652644
/*
653645
* Allocate the resource for MSG TLP before programming the iATU
654646
* outbound window in dw_pcie_setup_rc(). Since the allocation depends
@@ -915,8 +907,21 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
915907
* NOTE: For outbound address translation, outbound iATU at index 0 is
916908
* reserved for CFG IOs (dw_pcie_other_conf_map_bus()), thus start at
917909
* index 1.
910+
*
911+
* If using ECAM, outbound iATU at index 0 and index 1 is reserved for
912+
* CFG IOs.
918913
*/
919-
ob_iatu_index = 1;
914+
if (pp->ecam_enabled) {
915+
ob_iatu_index = 2;
916+
ret = dw_pcie_config_ecam_iatu(pp);
917+
if (ret) {
918+
dev_err(pci->dev, "Failed to configure iATU in ECAM mode\n");
919+
return ret;
920+
}
921+
} else {
922+
ob_iatu_index = 1;
923+
}
924+
920925
resource_list_for_each_entry(entry, &pp->bridge->windows) {
921926
resource_size_t res_size;
922927

@@ -985,8 +990,14 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
985990
* be shared between I/O space and CFG IOs, by
986991
* temporarily reconfiguring the iATU to CFG space, in
987992
* order to do a CFG IO, and then immediately restoring
988-
* it to I/O space.
993+
* it to I/O space. This is only implemented when using
994+
* dw_pcie_other_conf_map_bus(), which is not the case
995+
* when using ECAM.
989996
*/
997+
if (pp->ecam_enabled) {
998+
dev_err(pci->dev, "Cannot add outbound window for I/O\n");
999+
return -ENOMEM;
1000+
}
9901001
pp->cfg0_io_shared = true;
9911002
}
9921003
}
@@ -1157,7 +1168,7 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
11571168
* the platform uses its own address translation component rather than
11581169
* ATU, so we should not program the ATU here.
11591170
*/
1160-
if (pp->bridge->child_ops == &dw_child_pcie_ops) {
1171+
if (pp->bridge->child_ops == &dw_child_pcie_ops || pp->ecam_enabled) {
11611172
ret = dw_pcie_iatu_setup(pp);
11621173
if (ret)
11631174
return ret;

drivers/pci/controller/dwc/pcie-designware.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,9 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci,
532532
u32 retries, val;
533533
u64 limit_addr;
534534

535+
if (atu->index >= pci->num_ob_windows)
536+
return -ENOSPC;
537+
535538
limit_addr = parent_bus_addr + atu->size - 1;
536539

537540
if ((limit_addr & ~pci->region_limit) != (parent_bus_addr & ~pci->region_limit) ||
@@ -605,6 +608,9 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
605608
u64 limit_addr = pci_addr + size - 1;
606609
u32 retries, val;
607610

611+
if (index >= pci->num_ib_windows)
612+
return -ENOSPC;
613+
608614
if ((limit_addr & ~pci->region_limit) != (pci_addr & ~pci->region_limit) ||
609615
!IS_ALIGNED(parent_bus_addr, pci->region_align) ||
610616
!IS_ALIGNED(pci_addr, pci->region_align) || !size) {

0 commit comments

Comments
 (0)