Skip to content

Commit a1978b6

Browse files
PCI: dwc: Use custom pci_ops for root bus DBI vs ECAM config access
When the vendor configuration space is 256MB aligned, the DesignWare PCIe host driver enables ECAM access and sets the DBI base to the start of the config space. This causes vendor drivers to incorrectly program iATU regions, as they rely on the DBI address for internal accesses. To fix this, avoid overwriting the DBI base when ECAM is enabled. Instead, introduce a custom pci_ops that accesses the DBI region directly for the root bus and uses ECAM for other buses. Fixes: f6fd357 ("PCI: dwc: Prepare the driver for enabling ECAM mechanism using iATU 'CFG Shift Feature'") Reported-by: Ron Economos <[email protected]> Closes: https://lore.kernel.org/all/[email protected]/ Suggested-by: Manivannan Sadhasivam <[email protected]> Signed-off-by: Krishna Chaitanya Chundru <[email protected]> [bhelgaas: commit log] Signed-off-by: Bjorn Helgaas <[email protected]> Tested-by: Ron Economos <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent 3a86608 commit a1978b6

File tree

1 file changed

+24
-4
lines changed

1 file changed

+24
-4
lines changed

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

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "pcie-designware.h"
2424

2525
static struct pci_ops dw_pcie_ops;
26+
static struct pci_ops dw_pcie_ecam_ops;
2627
static struct pci_ops dw_child_pcie_ops;
2728

2829
#define DW_PCIE_MSI_FLAGS_REQUIRED (MSI_FLAG_USE_DEF_DOM_OPS | \
@@ -471,9 +472,6 @@ static int dw_pcie_create_ecam_window(struct dw_pcie_rp *pp, struct resource *re
471472
if (IS_ERR(pp->cfg))
472473
return PTR_ERR(pp->cfg);
473474

474-
pci->dbi_base = pp->cfg->win;
475-
pci->dbi_phys_addr = res->start;
476-
477475
return 0;
478476
}
479477

@@ -529,7 +527,7 @@ static int dw_pcie_host_get_resources(struct dw_pcie_rp *pp)
529527
if (ret)
530528
return ret;
531529

532-
pp->bridge->ops = (struct pci_ops *)&pci_generic_ecam_ops.pci_ops;
530+
pp->bridge->ops = &dw_pcie_ecam_ops;
533531
pp->bridge->sysdata = pp->cfg;
534532
pp->cfg->priv = pp;
535533
} else {
@@ -842,12 +840,34 @@ void __iomem *dw_pcie_own_conf_map_bus(struct pci_bus *bus, unsigned int devfn,
842840
}
843841
EXPORT_SYMBOL_GPL(dw_pcie_own_conf_map_bus);
844842

843+
static void __iomem *dw_pcie_ecam_conf_map_bus(struct pci_bus *bus, unsigned int devfn, int where)
844+
{
845+
struct pci_config_window *cfg = bus->sysdata;
846+
struct dw_pcie_rp *pp = cfg->priv;
847+
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
848+
unsigned int busn = bus->number;
849+
850+
if (busn > 0)
851+
return pci_ecam_map_bus(bus, devfn, where);
852+
853+
if (PCI_SLOT(devfn) > 0)
854+
return NULL;
855+
856+
return pci->dbi_base + where;
857+
}
858+
845859
static struct pci_ops dw_pcie_ops = {
846860
.map_bus = dw_pcie_own_conf_map_bus,
847861
.read = pci_generic_config_read,
848862
.write = pci_generic_config_write,
849863
};
850864

865+
static struct pci_ops dw_pcie_ecam_ops = {
866+
.map_bus = dw_pcie_ecam_conf_map_bus,
867+
.read = pci_generic_config_read,
868+
.write = pci_generic_config_write,
869+
};
870+
851871
static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
852872
{
853873
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);

0 commit comments

Comments
 (0)