summaryrefslogtreecommitdiff
path: root/drivers/pci/probe.c
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2018-06-07 00:10:08 +0300
committerBjorn Helgaas <bhelgaas@google.com>2018-06-07 00:10:08 +0300
commit5e3165d1a813cba0e7fad3880f9d704241e31245 (patch)
treece0f3f3f6c3d7c702fef408279869b95055f8b47 /drivers/pci/probe.c
parent8e069da28dfb09b78938395ebfb45a279507faf3 (diff)
parente5b1db0186bfb3bede41e412b27c9bcf2b336622 (diff)
downloadlinux-5e3165d1a813cba0e7fad3880f9d704241e31245.tar.xz
Merge branch 'pci/enumeration'
- neaten pci=earlydump output (Andy Shevchenko) - avoid errors when extended config space inaccessible (Gilles Buloz) - prevent sysfs disable of device while driver attached (Christoph Hellwig) - use core interface to report PCIe link properties in bnx2x, bnxt_en, cxgb4, ixgbe (Bjorn Helgaas) - remove unused pcie_get_minimum_link() (Bjorn Helgaas) * pci/enumeration: PCI: Remove unused pcie_get_minimum_link() ixgbe: Report PCIe link properties with pcie_print_link_status() cxgb4: Report PCIe link properties with pcie_print_link_status() bnxt_en: Report PCIe link properties with pcie_print_link_status() bnx2x: Report PCIe link properties with pcie_print_link_status() PCI: Prevent sysfs disable of device while driver is attached PCI: Check whether bridges allow access to extended config space x86/PCI: Make pci=earlydump output neat
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r--drivers/pci/probe.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index cc1688d75664..4fd402946b43 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -883,6 +883,45 @@ free:
return err;
}
+static bool pci_bridge_child_ext_cfg_accessible(struct pci_dev *bridge)
+{
+ int pos;
+ u32 status;
+
+ /*
+ * If extended config space isn't accessible on a bridge's primary
+ * bus, we certainly can't access it on the secondary bus.
+ */
+ if (bridge->bus->bus_flags & PCI_BUS_FLAGS_NO_EXTCFG)
+ return false;
+
+ /*
+ * PCIe Root Ports and switch ports are PCIe on both sides, so if
+ * extended config space is accessible on the primary, it's also
+ * accessible on the secondary.
+ */
+ if (pci_is_pcie(bridge) &&
+ (pci_pcie_type(bridge) == PCI_EXP_TYPE_ROOT_PORT ||
+ pci_pcie_type(bridge) == PCI_EXP_TYPE_UPSTREAM ||
+ pci_pcie_type(bridge) == PCI_EXP_TYPE_DOWNSTREAM))
+ return true;
+
+ /*
+ * For the other bridge types:
+ * - PCI-to-PCI bridges
+ * - PCIe-to-PCI/PCI-X forward bridges
+ * - PCI/PCI-X-to-PCIe reverse bridges
+ * extended config space on the secondary side is only accessible
+ * if the bridge supports PCI-X Mode 2.
+ */
+ pos = pci_find_capability(bridge, PCI_CAP_ID_PCIX);
+ if (!pos)
+ return false;
+
+ pci_read_config_dword(bridge, pos + PCI_X_STATUS, &status);
+ return 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)
{
@@ -924,6 +963,16 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
pci_set_bus_of_node(child);
pci_set_bus_speed(child);
+ /*
+ * Check whether extended config space is accessible on the child
+ * bus. Note that we currently assume it is always accessible on
+ * the root bus.
+ */
+ if (!pci_bridge_child_ext_cfg_accessible(bridge)) {
+ child->bus_flags |= PCI_BUS_FLAGS_NO_EXTCFG;
+ pci_info(child, "extended config space not accessible\n");
+ }
+
/* Set up default resource pointers and names */
for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i];
@@ -1394,6 +1443,9 @@ int pci_cfg_space_size(struct pci_dev *dev)
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);