aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2014-05-05 16:20:51 -0400
committerBjorn Helgaas <bhelgaas@google.com>2014-05-27 17:07:41 -0400
commit78916b00f0096059c872f537306b1a464c84fb30 (patch)
treef3ef41ae8a54215c83ce51db6f3573305a48eb72 /drivers/pci
parent9edbcd2252b5ef148177c9f2c11a56469cf5db52 (diff)
PCI: Test for std config alias when testing extended config space
When a PCI-to-PCIe bridge is stacked on a PCIe-to-PCI bridge, we can have PCIe endpoints masked by a conventional PCI bus. This makes the extended config space of the PCIe endpoint inaccessible. The PCIe-to-PCI bridge is supposed to handle any type 1 configuration transactions where the extended config offset bits are non-zero as an Unsupported Request rather than forward it to the secondary interface. As noted here, there are a couple known offenders to this rule. These bridges drop the extended offset bits, resulting in the conventional config space being aliased many times across the extended config space. For Intel NICs, this alias often seems to expose a bogus SR-IOV cap. Stacking bridges may seem like an uncommon scenario, but note that any conventional PCI slot in a modern PC is already the secondary interface of an onboard PCIe-to-PCI bridge. The user need only add a PCI-to-PCIe adapter and PCIe device to encounter this problem. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/probe.c39
1 files changed, 38 insertions, 1 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 490031fd2108..b47c2dd5b9e1 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -984,6 +984,43 @@ void set_pcie_hotplug_bridge(struct pci_dev *pdev)
984 984
985 985
986/** 986/**
987 * pci_ext_cfg_is_aliased - is ext config space just an alias of std config?
988 * @dev: PCI device
989 *
990 * PCI Express to PCI/PCI-X Bridge Specification, rev 1.0, 4.1.4 says that
991 * when forwarding a type1 configuration request the bridge must check that
992 * the extended register address field is zero. The bridge is not permitted
993 * to forward the transactions and must handle it as an Unsupported Request.
994 * Some bridges do not follow this rule and simply drop the extended register
995 * bits, resulting in the standard config space being aliased, every 256
996 * bytes across the entire configuration space. Test for this condition by
997 * comparing the first dword of each potential alias to the vendor/device ID.
998 * Known offenders:
999 * ASM1083/1085 PCIe-to-PCI Reversible Bridge (1b21:1080, rev 01 & 03)
1000 * AMD/ATI SBx00 PCI to PCI Bridge (1002:4384, rev 40)
1001 */
1002static bool pci_ext_cfg_is_aliased(struct pci_dev *dev)
1003{
1004#ifdef CONFIG_PCI_QUIRKS
1005 int pos;
1006 u32 header, tmp;
1007
1008 pci_read_config_dword(dev, PCI_VENDOR_ID, &header);
1009
1010 for (pos = PCI_CFG_SPACE_SIZE;
1011 pos < PCI_CFG_SPACE_EXP_SIZE; pos += PCI_CFG_SPACE_SIZE) {
1012 if (pci_read_config_dword(dev, pos, &tmp) != PCIBIOS_SUCCESSFUL
1013 || header != tmp)
1014 return false;
1015 }
1016
1017 return true;
1018#else
1019 return false;
1020#endif
1021}
1022
1023/**
987 * pci_cfg_space_size - get the configuration space size of the PCI device. 1024 * pci_cfg_space_size - get the configuration space size of the PCI device.
988 * @dev: PCI device 1025 * @dev: PCI device
989 * 1026 *
@@ -1001,7 +1038,7 @@ static int pci_cfg_space_size_ext(struct pci_dev *dev)
1001 1038
1002 if (pci_read_config_dword(dev, pos, &status) != PCIBIOS_SUCCESSFUL) 1039 if (pci_read_config_dword(dev, pos, &status) != PCIBIOS_SUCCESSFUL)
1003 goto fail; 1040 goto fail;
1004 if (status == 0xffffffff) 1041 if (status == 0xffffffff || pci_ext_cfg_is_aliased(dev))
1005 goto fail; 1042 goto fail;
1006 1043
1007 return PCI_CFG_SPACE_EXP_SIZE; 1044 return PCI_CFG_SPACE_EXP_SIZE;