mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
PCI: iproc: Use the EROM outbound window on BCMA
The PCIe outbound window base on Northstar depends on the PCIe Gen2 core revision. Revision 0x01 uses 0x08000000, 0x40000000 and 0x48000000 for controllers 0 to 2, while revision 0x07 (NS-B0) uses 0x08000000, 0x20000000 and 0x28000000. Broadcom's own driver branches on the core revision for exactly this reason. bcm-ns.dtsi is shared by every Northstar SoC, so it cannot carry a value that is correct on both. Commit7670123979("ARM: dts: BCM5301X: Describe PCIe controllers fully") gave the controllers a ranges property. The commit shipped in v7.1. With that property present, two things go wrong with this driver: 1) devm_pci_alloc_host_bridge() parses those ranges and requests them, then this driver adds its own window and requests the whole list a second time, so every controller fails to probe with -EBUSY. 2) The DT window itself is only correct on core revision 0x07. On revision 0x01 it points at an address the hardware does not decode, and the first MMIO access to a BAR takes an imprecise external abort. The enumeration ROM reports the correct base for the revision actually present, and bcma already provides it as addr_s[0]. To solve 1), use pci_alloc_host_bridge() directly to avoid the request of all the DT resources done in pci_parse_request_of_pci_ranges(). Instead, request the memory window from the EROM. To solve 2), parse the memory resources from DT and emit a warning if it describes a window that doesn't match the window from the EROM. The mismatch means the devicetree describes a window the hardware does not decode, and that should be fixed in the dts rather than ignored silently. The driver is correct whether or not the DT describes a window. The same commit also added compatible = "brcm,iproc-pcie", so these nodes now match pcie-iproc-platform. With CONFIG_PCIE_IPROC_PLATFORM enabled, which is the default on ARCH_BCM_IPROC, that driver binds them first and this driver's probe fails inside devm_pci_alloc_host_bridge(). This commit fixes the configurations where the BCMA driver is the one in use; OpenWrt builds that way, with PCIE_IPROC_PLATFORM disabled. The platform path takes the DT window as-is and has the same wrong address on core revision 0x01, so that side needs a devicetree fix either way. Based on: https://patch.msgid.link/20260807160526.379-1-strst.gs@gmail.com https://patch.msgid.link/20260912043626.437-1-strst.gs@gmail.com Fixes:7670123979("ARM: dts: BCM5301X: Describe PCIe controllers fully") Signed-off-by: Semih Baskan <strst.gs@gmail.com> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@oss.qualcomm.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Tested-by: Semih Baskan <strst.gs@gmail.com> Link: https://patch.msgid.link/20261013220421.1588051-3-bhelgaas@google.com
This commit is contained in:
parent
39d1c645bb
commit
9850907ee1
|
|
@ -11,7 +11,9 @@
|
|||
#include <linux/phy/phy.h>
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#include "../pci.h"
|
||||
#include "pcie-iproc.h"
|
||||
|
||||
|
||||
|
|
@ -31,6 +33,29 @@ static int iproc_bcma_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
|||
return bcma_core_irq(bdev, 5);
|
||||
}
|
||||
|
||||
static void iproc_bcma_pcie_check_dt_window(struct iproc_pcie *pcie)
|
||||
{
|
||||
struct device_node *np = pcie->dev->of_node;
|
||||
struct of_pci_range_parser parser;
|
||||
struct of_pci_range range;
|
||||
struct resource res;
|
||||
|
||||
if (!np || of_pci_range_parser_init(&parser, np))
|
||||
return;
|
||||
|
||||
for_each_of_pci_range(&parser, &range) {
|
||||
if ((range.flags & IORESOURCE_TYPE_BITS) != IORESOURCE_MEM)
|
||||
continue;
|
||||
|
||||
if (of_pci_range_to_resource(&range, np, &res))
|
||||
continue;
|
||||
|
||||
if (res.start != pcie->mem.start || res.end != pcie->mem.end)
|
||||
dev_warn(pcie->dev, "DT window %pR does not match EROM window %pR, using EROM\n",
|
||||
&res, &pcie->mem);
|
||||
}
|
||||
}
|
||||
|
||||
static int iproc_bcma_pcie_probe(struct bcma_device *bdev)
|
||||
{
|
||||
struct device *dev = &bdev->dev;
|
||||
|
|
@ -38,10 +63,20 @@ static int iproc_bcma_pcie_probe(struct bcma_device *bdev)
|
|||
struct pci_host_bridge *bridge;
|
||||
int ret;
|
||||
|
||||
bridge = devm_pci_alloc_host_bridge(dev, sizeof(*pcie));
|
||||
bridge = pci_alloc_host_bridge(sizeof(*pcie));
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
bridge->dev.parent = dev;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, devm_pci_alloc_host_bridge_release,
|
||||
bridge);
|
||||
if (ret)
|
||||
return -ENOMEM;
|
||||
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
bridge->map_irq = iproc_bcma_pcie_map_irq;
|
||||
|
||||
pcie = pci_host_bridge_priv(bridge);
|
||||
|
||||
pcie->dev = dev;
|
||||
|
|
@ -59,13 +94,12 @@ static int iproc_bcma_pcie_probe(struct bcma_device *bdev)
|
|||
pcie->mem.end = bdev->addr_s[0] + SZ_128M - 1;
|
||||
pcie->mem.name = "PCIe MEM space";
|
||||
pcie->mem.flags = IORESOURCE_MEM;
|
||||
iproc_bcma_pcie_check_dt_window(pcie);
|
||||
pci_add_resource(&bridge->windows, &pcie->mem);
|
||||
ret = devm_request_pci_bus_resources(dev, &bridge->windows);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
bridge->map_irq = iproc_bcma_pcie_map_irq;
|
||||
|
||||
bcma_set_drvdata(bdev, pcie);
|
||||
|
||||
return iproc_pcie_setup(pcie, &bridge->windows);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user