Depending on the capabilities of the PCI controller/platform, the PCI-to-PCI bridge emulation behavior might need to be different. For example, on platforms that use the pci-mvebu code, we currently don't support prefetchable memory BARs, so the corresponding fields in the PCI-to-PCI bridge configuration space should be read-only. To implement this, this commit extends pci_bridge_emul_init() to take a "flags" argument, with currently one flag supported: PCI_BRIDGE_EMUL_NO_PREFETCHABLE_BAR, that will make the prefetchable memory base and limit registers read-only. The pci-mvebu and pci-aardvark drivers are updated accordingly. Reported-by: Luís Mendes <luis.p.mendes@xxxxxxxxx> Reported-by: Leigh Brown <leigh@xxxxxxxxxxxxx> Cc: Luís Mendes <luis.p.mendes@xxxxxxxxx> Cc: Leigh Brown <leigh@xxxxxxxxxxxxx> Fixes: 1f08673eef123 ("PCI: mvebu: Convert to PCI emulated bridge config space") Signed-off-by: Thomas Petazzoni <thomas.petazzoni@xxxxxxxxxxx> --- drivers/pci/controller/pci-aardvark.c | 2 +- drivers/pci/controller/pci-mvebu.c | 2 +- drivers/pci/pci-bridge-emul.c | 8 +++++++- drivers/pci/pci-bridge-emul.h | 7 ++++++- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 750081c1cb48..6eecae447af3 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -499,7 +499,7 @@ static void advk_sw_pci_bridge_init(struct advk_pcie *pcie) bridge->data = pcie; bridge->ops = &advk_pci_bridge_emul_ops; - pci_bridge_emul_init(bridge); + pci_bridge_emul_init(bridge, 0); } diff --git a/drivers/pci/controller/pci-mvebu.c b/drivers/pci/controller/pci-mvebu.c index fa0fc46edb0c..d3a0419e42f2 100644 --- a/drivers/pci/controller/pci-mvebu.c +++ b/drivers/pci/controller/pci-mvebu.c @@ -583,7 +583,7 @@ static void mvebu_pci_bridge_emul_init(struct mvebu_pcie_port *port) bridge->data = port; bridge->ops = &mvebu_pci_bridge_emul_ops; - pci_bridge_emul_init(bridge); + pci_bridge_emul_init(bridge, PCI_BRIDGE_EMUL_NO_PREFETCHABLE_BAR); } static inline struct mvebu_pcie *sys_to_pcie(struct pci_sys_data *sys) diff --git a/drivers/pci/pci-bridge-emul.c b/drivers/pci/pci-bridge-emul.c index dd8d8060317e..83fb077d0b41 100644 --- a/drivers/pci/pci-bridge-emul.c +++ b/drivers/pci/pci-bridge-emul.c @@ -267,7 +267,8 @@ const static struct pci_bridge_reg_behavior pcie_cap_regs_behavior[] = { * (typically at least vendor, device, revision), the ->ops pointer, * and optionally ->data and ->has_pcie. */ -int pci_bridge_emul_init(struct pci_bridge_emul *bridge) +int pci_bridge_emul_init(struct pci_bridge_emul *bridge, + unsigned int flags) { bridge->conf.class_revision |= PCI_CLASS_BRIDGE_PCI << 16; bridge->conf.header_type = PCI_HEADER_TYPE_BRIDGE; @@ -295,6 +296,11 @@ int pci_bridge_emul_init(struct pci_bridge_emul *bridge) } } + if (flags & PCI_BRIDGE_EMUL_NO_PREFETCHABLE_BAR) { + bridge->pci_regs_behavior[PCI_PREF_MEMORY_BASE / 4].ro = ~0; + bridge->pci_regs_behavior[PCI_PREF_MEMORY_BASE / 4].rw = 0; + } + return 0; } diff --git a/drivers/pci/pci-bridge-emul.h b/drivers/pci/pci-bridge-emul.h index f04637bb3222..e65b1b79899d 100644 --- a/drivers/pci/pci-bridge-emul.h +++ b/drivers/pci/pci-bridge-emul.h @@ -119,7 +119,12 @@ struct pci_bridge_emul { bool has_pcie; }; -int pci_bridge_emul_init(struct pci_bridge_emul *bridge); +enum { + PCI_BRIDGE_EMUL_NO_PREFETCHABLE_BAR = BIT(0), +}; + +int pci_bridge_emul_init(struct pci_bridge_emul *bridge, + unsigned int flags); void pci_bridge_emul_cleanup(struct pci_bridge_emul *bridge); int pci_bridge_emul_conf_read(struct pci_bridge_emul *bridge, int where, -- 2.20.1