=====================
Gilles BULOZ
Senior software engineer
Kontron France
=====================
Signed-off-by: Gilles Buloz <gilles.buloz@kontron.com>
@@ -217,6 +217,7 @@ enum pci_bus_flags {
PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1,
PCI_BUS_FLAGS_NO_MMRBC = (__force pci_bus_flags_t) 2,
PCI_BUS_FLAGS_NO_AERSID = (__force pci_bus_flags_t) 4,
+ PCI_BUS_FLAGS_NO_EXTCFG = (__force pci_bus_flags_t) 8,
};
/* Values from Link Status register, PCIe r3.1, sec 7.8.8 */
@@ -882,6 +882,24 @@ free:
return err;
}
+static bool pci_bridge_child_bus_ext_cfg_accessible(struct pci_dev *bridge)
+{
+ int pos;
+ u32 status;
+
+ if (pci_is_pcie(bridge) &&
+ (pci_pcie_type(bridge) != PCI_EXP_TYPE_PCIE_BRIDGE) &&
+ (pci_pcie_type(bridge) != PCI_EXP_TYPE_PCI_BRIDGE))
+ return true;
+
+ /* PCI/PCI, or PCIe/PCI (forward), or PCI/PCIe (reverse) bridge */
+ pos = pci_find_capability(bridge, PCI_CAP_ID_PCIX);
+ if (pos)
+ pci_read_config_dword(bridge, pos + PCI_X_STATUS, &status);
+
+ return pos && (status & (PCI_X_STATUS_266MHZ | PCI_X_STATUS_533MHZ));
+}
+
static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
struct pci_dev *bridge, int busnr)
{
@@ -930,6 +948,20 @@ static struct pci_bus *pci_alloc_child_b
}
bridge->subordinate = child;
+ /*
+ * if bus_flags inherited from parent bus do not already report lack of
+ * extended config space support, check if supported by child bus by
+ * checking its parent bridge
+ */
+ if (child->bus_flags & PCI_BUS_FLAGS_NO_EXTCFG) {
+ pci_info(child, "extended config space not accessible due to parent bus\n");
+ } else {
+ if (!pci_bridge_child_bus_ext_cfg_accessible(bridge)) {
+ child->bus_flags |= PCI_BUS_FLAGS_NO_EXTCFG;
+ pci_info(child, "extended config space not accessible due to parent bridge\n");
+ }
+ }
+
add_dev:
pci_set_bus_msi_domain(child);
ret = device_register(&child->dev);
@@ -1393,6 +1425,9 @@ int pci_cfg_space_size(struct pci_dev *d
u32 status;
u16 class;
+ if (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_EXTCFG)
+ return PCI_CFG_SPACE_SIZE;
+
class = dev->class >> 8;
if (class == PCI_CLASS_BRIDGE_HOST)
return pci_cfg_space_size_ext(dev);