diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2014-05-28 16:21:25 -0600 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2014-05-28 16:21:25 -0600 |
commit | fdaf36bd360fe1e74b34262ad705ef39d52c12de (patch) | |
tree | b686d69b0c5bf74ac0cd704123d64bfcdb3c10f5 /drivers/pci/probe.c | |
parent | d1a2523d2adc0b6910dbc2a9aed44c4217134db1 (diff) | |
parent | d97ffe236894856d08146390ef3fbe6448a8ac2b (diff) | |
download | linux-fdaf36bd360fe1e74b34262ad705ef39d52c12de.tar.bz2 |
Merge branch 'pci/misc' into next
* pci/misc:
PCI: Fix return value from pci_user_{read,write}_config_*()
PCI: Turn pcibios_penalize_isa_irq() into a weak function
PCI: Test for std config alias when testing extended config space
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r-- | drivers/pci/probe.c | 39 |
1 files changed, 38 insertions, 1 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 36f1fd174b07..2bbf5221afb3 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -994,6 +994,43 @@ void set_pcie_hotplug_bridge(struct pci_dev *pdev) /** + * pci_ext_cfg_is_aliased - is ext config space just an alias of std config? + * @dev: PCI device + * + * PCI Express to PCI/PCI-X Bridge Specification, rev 1.0, 4.1.4 says that + * when forwarding a type1 configuration request the bridge must check that + * the extended register address field is zero. The bridge is not permitted + * to forward the transactions and must handle it as an Unsupported Request. + * Some bridges do not follow this rule and simply drop the extended register + * bits, resulting in the standard config space being aliased, every 256 + * bytes across the entire configuration space. Test for this condition by + * comparing the first dword of each potential alias to the vendor/device ID. + * Known offenders: + * ASM1083/1085 PCIe-to-PCI Reversible Bridge (1b21:1080, rev 01 & 03) + * AMD/ATI SBx00 PCI to PCI Bridge (1002:4384, rev 40) + */ +static bool pci_ext_cfg_is_aliased(struct pci_dev *dev) +{ +#ifdef CONFIG_PCI_QUIRKS + int pos; + u32 header, tmp; + + pci_read_config_dword(dev, PCI_VENDOR_ID, &header); + + for (pos = PCI_CFG_SPACE_SIZE; + pos < PCI_CFG_SPACE_EXP_SIZE; pos += PCI_CFG_SPACE_SIZE) { + if (pci_read_config_dword(dev, pos, &tmp) != PCIBIOS_SUCCESSFUL + || header != tmp) + return false; + } + + return true; +#else + return false; +#endif +} + +/** * pci_cfg_space_size - get the configuration space size of the PCI device. * @dev: PCI device * @@ -1011,7 +1048,7 @@ static int pci_cfg_space_size_ext(struct pci_dev *dev) if (pci_read_config_dword(dev, pos, &status) != PCIBIOS_SUCCESSFUL) goto fail; - if (status == 0xffffffff) + if (status == 0xffffffff || pci_ext_cfg_is_aliased(dev)) goto fail; return PCI_CFG_SPACE_EXP_SIZE; |