From: Bjorn Helgaas <bhelgaas@xxxxxxxxxx> Set pp->parent_bus_offset based on the parent bus address from the "config" reg entry if it exists. .cpu_addr_fixup(res->start) (if implemented) should return the parent bus address corresponding to res->start. Sets pp->parent_bus_offset, but doesn't use it, so no functional change intended yet. --- .../pci/controller/dwc/pcie-designware-host.c | 42 +++++++++++++++++++ drivers/pci/controller/dwc/pcie-designware.h | 1 + 2 files changed, 43 insertions(+) diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index b9eaba157dae..e22f650ada5a 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -423,7 +423,11 @@ static int dw_pcie_cfg0_setup(struct dw_pcie_rp *pp) struct dw_pcie *pci = to_dw_pcie_from_pp(pp); struct device *dev = pci->dev; struct platform_device *pdev = to_platform_device(dev); + struct device_node *np = dev->of_node; struct resource *res; + int index; + u64 reg_addr, fixup_addr; + u64 (*fixup)(struct dw_pcie *pcie, u64 cpu_addr); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config"); if (!res) { @@ -434,6 +438,44 @@ static int dw_pcie_cfg0_setup(struct dw_pcie_rp *pp) pp->cfg0_size = resource_size(res); pp->cfg0_base = res->start; + /* [mem 0x7ff00000-] in example */ + dev_info(dev, "%pR config CPU physical\n", res); + + /* Look up "config" address on parent bus */ + reg_addr = 0; + index = of_property_match_string(np, "reg-names", "config"); + if (index >= 0) { + of_property_read_reg(np, index, ®_addr, NULL); + /* [ia 0x8ff00000-] in example */ + dev_info(dev, "%#010llx config reg[%d] parent bus addr\n", + reg_addr, index); + } else { + reg_addr = res->start; + dev_warn(dev, "%#010llx assumed parent bus addr (no config reg-names entry)\n", + reg_addr); + } + + fixup = pci->ops->cpu_addr_fixup; + if (fixup) { + fixup_addr = fixup(pci, res->start); + dev_info(dev, "%#010llx result of %ps(%#010llx)\n", + fixup_addr, fixup, res->start); + if (reg_addr == fixup_addr) { + dev_info(dev, "%#010llx config reg[%d] == %#010llx; %ps is redundant\n", + reg_addr, index, fixup_addr, fixup); + } else { + dev_warn(dev, "%#010llx config reg[%d] != %#010llx fixed up addr; DT is broken\n", + reg_addr, index, fixup_addr); + reg_addr = fixup_addr; + } + } + + /* 0x7ff00000 - 0x8ff00000 == 0xf0000000 */ + pp->parent_bus_offset = res->start - reg_addr; + dev_info(dev, "%#010llx config parent bus offset\n", + pp->parent_bus_offset); + + pp->va_cfg0_base = devm_pci_remap_cfg_resource(dev, res); if (IS_ERR(pp->va_cfg0_base)) return PTR_ERR(pp->va_cfg0_base); diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index ac23604c829f..eeca38ec3a2b 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -362,6 +362,7 @@ struct dw_pcie_rp { u64 cfg0_base; void __iomem *va_cfg0_base; u32 cfg0_size; + u64 parent_bus_offset; resource_size_t io_base; phys_addr_t io_bus_addr; u32 io_size; -- 2.34.1