Message ID | 20250315201548.858189-7-helgaas@kernel.org (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | PCI: Use device bus range info to cleanup RC Host/EP pci_fixup_addr() | expand |
On Sat, Mar 15, 2025 at 03:15:41PM -0500, Bjorn Helgaas wrote: > From: Frank Li <Frank.Li@nxp.com> > > dw_pcie_parent_bus_offset() looks up the parent bus address of a PCI > controller 'reg' property in devicetree. If implemented, .cpu_addr_fixup() > is a hard-coded way to get the parent bus address corresponding to a CPU > physical address. > > Add debug code to compare the address from .cpu_addr_fixup() with the > address from devicetree. If they match, warn that .cpu_addr_fixup() is > redundant and should be removed; if they differ, warn that something is > wrong with the devicetree. > > If .cpu_addr_fixup() is not implemented, the parent bus address should be > identical to the CPU physical address because we previously ignored the > parent bus address from devicetree. If the devicetree has a different > parent bus address, warn about it being broken. > > [bhelgaas: split debug to separate patch for easier future revert, commit > log] > Link: https://lore.kernel.org/r/20250313-pci_fixup_addr-v11-5-01d2313502ab@nxp.com > Signed-off-by: Frank Li <Frank.Li@nxp.com> > Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> > --- > drivers/pci/controller/dwc/pcie-designware.c | 26 +++++++++++++++++++- > drivers/pci/controller/dwc/pcie-designware.h | 13 ++++++++++ > 2 files changed, 38 insertions(+), 1 deletion(-) > > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c > index 0a35e36da703..985264c88b92 100644 > --- a/drivers/pci/controller/dwc/pcie-designware.c > +++ b/drivers/pci/controller/dwc/pcie-designware.c > @@ -1114,7 +1114,8 @@ resource_size_t dw_pcie_parent_bus_offset(struct dw_pcie *pci, > struct device *dev = pci->dev; > struct device_node *np = dev->of_node; > int index; > - u64 reg_addr; > + u64 reg_addr, fixup_addr; > + u64 (*fixup)(struct dw_pcie *pcie, u64 cpu_addr); > > /* Look up reg_name address on parent bus */ > index = of_property_match_string(np, "reg-names", reg_name); > @@ -1126,5 +1127,28 @@ resource_size_t dw_pcie_parent_bus_offset(struct dw_pcie *pci, > > of_property_read_reg(np, index, ®_addr, NULL); > > + fixup = pci->ops->cpu_addr_fixup; > + if (fixup) { > + fixup_addr = fixup(pci, cpu_phy_addr); > + if (reg_addr == fixup_addr) { > + dev_warn(dev, "%#010llx %s reg[%d] == %#010llx; %ps is redundant\n", > + cpu_phy_addr, reg_name, index, > + fixup_addr, fixup); > + } else { > + dev_warn(dev, "%#010llx %s reg[%d] != %#010llx fixed up addr; devicetree is broken\n", > + cpu_phy_addr, reg_name, > + index, fixup_addr); > + reg_addr = fixup_addr; > + } > + } else if (!pci->use_parent_dt_ranges) { > + if (reg_addr != cpu_phy_addr) { > + dev_warn(dev, "devicetree has incorrect translation; please check parent \"ranges\" property. CPU physical addr %#010llx, parent bus addr %#010llx\n", > + cpu_phy_addr, reg_addr); > + return 0; > + } > + } > + > + dev_info(dev, "%s parent bus offset is %#010llx\n", > + reg_name, cpu_phy_addr - reg_addr); > return cpu_phy_addr - reg_addr; > } > diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h > index 16548b01347d..f08d2852cfd5 100644 > --- a/drivers/pci/controller/dwc/pcie-designware.h > +++ b/drivers/pci/controller/dwc/pcie-designware.h > @@ -465,6 +465,19 @@ struct dw_pcie { > struct reset_control_bulk_data core_rsts[DW_PCIE_NUM_CORE_RSTS]; > struct gpio_desc *pe_rst; > bool suspended; > + > + /* > + * If iATU input addresses are offset from CPU physical addresses, > + * we previously required .cpu_addr_fixup() to convert them. We > + * now rely on the devicetree instead. If .cpu_addr_fixup() > + * exists, we compare its results with devicetree. > + * > + * If .cpu_addr_fixup() does not exist, we assume the offset is > + * zero and warn if devicetree claims otherwise. If we know all > + * devicetrees correctly describe the offset, set > + * use_parent_dt_ranges to true to avoid this warning. > + */ > + bool use_parent_dt_ranges; Look good. Frank > }; > > #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp) > -- > 2.34.1 >
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c index 0a35e36da703..985264c88b92 100644 --- a/drivers/pci/controller/dwc/pcie-designware.c +++ b/drivers/pci/controller/dwc/pcie-designware.c @@ -1114,7 +1114,8 @@ resource_size_t dw_pcie_parent_bus_offset(struct dw_pcie *pci, struct device *dev = pci->dev; struct device_node *np = dev->of_node; int index; - u64 reg_addr; + u64 reg_addr, fixup_addr; + u64 (*fixup)(struct dw_pcie *pcie, u64 cpu_addr); /* Look up reg_name address on parent bus */ index = of_property_match_string(np, "reg-names", reg_name); @@ -1126,5 +1127,28 @@ resource_size_t dw_pcie_parent_bus_offset(struct dw_pcie *pci, of_property_read_reg(np, index, ®_addr, NULL); + fixup = pci->ops->cpu_addr_fixup; + if (fixup) { + fixup_addr = fixup(pci, cpu_phy_addr); + if (reg_addr == fixup_addr) { + dev_warn(dev, "%#010llx %s reg[%d] == %#010llx; %ps is redundant\n", + cpu_phy_addr, reg_name, index, + fixup_addr, fixup); + } else { + dev_warn(dev, "%#010llx %s reg[%d] != %#010llx fixed up addr; devicetree is broken\n", + cpu_phy_addr, reg_name, + index, fixup_addr); + reg_addr = fixup_addr; + } + } else if (!pci->use_parent_dt_ranges) { + if (reg_addr != cpu_phy_addr) { + dev_warn(dev, "devicetree has incorrect translation; please check parent \"ranges\" property. CPU physical addr %#010llx, parent bus addr %#010llx\n", + cpu_phy_addr, reg_addr); + return 0; + } + } + + dev_info(dev, "%s parent bus offset is %#010llx\n", + reg_name, cpu_phy_addr - reg_addr); return cpu_phy_addr - reg_addr; } diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h index 16548b01347d..f08d2852cfd5 100644 --- a/drivers/pci/controller/dwc/pcie-designware.h +++ b/drivers/pci/controller/dwc/pcie-designware.h @@ -465,6 +465,19 @@ struct dw_pcie { struct reset_control_bulk_data core_rsts[DW_PCIE_NUM_CORE_RSTS]; struct gpio_desc *pe_rst; bool suspended; + + /* + * If iATU input addresses are offset from CPU physical addresses, + * we previously required .cpu_addr_fixup() to convert them. We + * now rely on the devicetree instead. If .cpu_addr_fixup() + * exists, we compare its results with devicetree. + * + * If .cpu_addr_fixup() does not exist, we assume the offset is + * zero and warn if devicetree claims otherwise. If we know all + * devicetrees correctly describe the offset, set + * use_parent_dt_ranges to true to avoid this warning. + */ + bool use_parent_dt_ranges; }; #define to_dw_pcie_from_pp(port) container_of((port), struct dw_pcie, pp)