diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2014-05-28 18:21:25 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2014-05-28 18:21:25 -0400 |
commit | fdaf36bd360fe1e74b34262ad705ef39d52c12de (patch) | |
tree | b686d69b0c5bf74ac0cd704123d64bfcdb3c10f5 /drivers/pci | |
parent | d1a2523d2adc0b6910dbc2a9aed44c4217134db1 (diff) | |
parent | d97ffe236894856d08146390ef3fbe6448a8ac2b (diff) |
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')
-rw-r--r-- | drivers/pci/access.c | 12 | ||||
-rw-r--r-- | drivers/pci/pci.c | 11 | ||||
-rw-r--r-- | drivers/pci/probe.c | 39 |
3 files changed, 53 insertions, 9 deletions
diff --git a/drivers/pci/access.c b/drivers/pci/access.c index 7f8b78c08879..8c148f39e8d7 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c | |||
@@ -148,7 +148,7 @@ static noinline void pci_wait_cfg(struct pci_dev *dev) | |||
148 | int pci_user_read_config_##size \ | 148 | int pci_user_read_config_##size \ |
149 | (struct pci_dev *dev, int pos, type *val) \ | 149 | (struct pci_dev *dev, int pos, type *val) \ |
150 | { \ | 150 | { \ |
151 | int ret = 0; \ | 151 | int ret = PCIBIOS_SUCCESSFUL; \ |
152 | u32 data = -1; \ | 152 | u32 data = -1; \ |
153 | if (PCI_##size##_BAD) \ | 153 | if (PCI_##size##_BAD) \ |
154 | return -EINVAL; \ | 154 | return -EINVAL; \ |
@@ -159,9 +159,7 @@ int pci_user_read_config_##size \ | |||
159 | pos, sizeof(type), &data); \ | 159 | pos, sizeof(type), &data); \ |
160 | raw_spin_unlock_irq(&pci_lock); \ | 160 | raw_spin_unlock_irq(&pci_lock); \ |
161 | *val = (type)data; \ | 161 | *val = (type)data; \ |
162 | if (ret > 0) \ | 162 | return pcibios_err_to_errno(ret); \ |
163 | ret = -EINVAL; \ | ||
164 | return ret; \ | ||
165 | } \ | 163 | } \ |
166 | EXPORT_SYMBOL_GPL(pci_user_read_config_##size); | 164 | EXPORT_SYMBOL_GPL(pci_user_read_config_##size); |
167 | 165 | ||
@@ -170,7 +168,7 @@ EXPORT_SYMBOL_GPL(pci_user_read_config_##size); | |||
170 | int pci_user_write_config_##size \ | 168 | int pci_user_write_config_##size \ |
171 | (struct pci_dev *dev, int pos, type val) \ | 169 | (struct pci_dev *dev, int pos, type val) \ |
172 | { \ | 170 | { \ |
173 | int ret = -EIO; \ | 171 | int ret = PCIBIOS_SUCCESSFUL; \ |
174 | if (PCI_##size##_BAD) \ | 172 | if (PCI_##size##_BAD) \ |
175 | return -EINVAL; \ | 173 | return -EINVAL; \ |
176 | raw_spin_lock_irq(&pci_lock); \ | 174 | raw_spin_lock_irq(&pci_lock); \ |
@@ -179,9 +177,7 @@ int pci_user_write_config_##size \ | |||
179 | ret = dev->bus->ops->write(dev->bus, dev->devfn, \ | 177 | ret = dev->bus->ops->write(dev->bus, dev->devfn, \ |
180 | pos, sizeof(type), val); \ | 178 | pos, sizeof(type), val); \ |
181 | raw_spin_unlock_irq(&pci_lock); \ | 179 | raw_spin_unlock_irq(&pci_lock); \ |
182 | if (ret > 0) \ | 180 | return pcibios_err_to_errno(ret); \ |
183 | ret = -EINVAL; \ | ||
184 | return ret; \ | ||
185 | } \ | 181 | } \ |
186 | EXPORT_SYMBOL_GPL(pci_user_write_config_##size); | 182 | EXPORT_SYMBOL_GPL(pci_user_write_config_##size); |
187 | 183 | ||
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index f988bb18eba5..fd958c8ebd83 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -1468,6 +1468,17 @@ void __weak pcibios_release_device(struct pci_dev *dev) {} | |||
1468 | */ | 1468 | */ |
1469 | void __weak pcibios_disable_device (struct pci_dev *dev) {} | 1469 | void __weak pcibios_disable_device (struct pci_dev *dev) {} |
1470 | 1470 | ||
1471 | /** | ||
1472 | * pcibios_penalize_isa_irq - penalize an ISA IRQ | ||
1473 | * @irq: ISA IRQ to penalize | ||
1474 | * @active: IRQ active or not | ||
1475 | * | ||
1476 | * Permits the platform to provide architecture-specific functionality when | ||
1477 | * penalizing ISA IRQs. This is the default implementation. Architecture | ||
1478 | * implementations can override this. | ||
1479 | */ | ||
1480 | void __weak pcibios_penalize_isa_irq(int irq, int active) {} | ||
1481 | |||
1471 | static void do_pci_disable_device(struct pci_dev *dev) | 1482 | static void do_pci_disable_device(struct pci_dev *dev) |
1472 | { | 1483 | { |
1473 | u16 pci_command; | 1484 | u16 pci_command; |
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) | |||
994 | 994 | ||
995 | 995 | ||
996 | /** | 996 | /** |
997 | * pci_ext_cfg_is_aliased - is ext config space just an alias of std config? | ||
998 | * @dev: PCI device | ||
999 | * | ||
1000 | * PCI Express to PCI/PCI-X Bridge Specification, rev 1.0, 4.1.4 says that | ||
1001 | * when forwarding a type1 configuration request the bridge must check that | ||
1002 | * the extended register address field is zero. The bridge is not permitted | ||
1003 | * to forward the transactions and must handle it as an Unsupported Request. | ||
1004 | * Some bridges do not follow this rule and simply drop the extended register | ||
1005 | * bits, resulting in the standard config space being aliased, every 256 | ||
1006 | * bytes across the entire configuration space. Test for this condition by | ||
1007 | * comparing the first dword of each potential alias to the vendor/device ID. | ||
1008 | * Known offenders: | ||
1009 | * ASM1083/1085 PCIe-to-PCI Reversible Bridge (1b21:1080, rev 01 & 03) | ||
1010 | * AMD/ATI SBx00 PCI to PCI Bridge (1002:4384, rev 40) | ||
1011 | */ | ||
1012 | static bool pci_ext_cfg_is_aliased(struct pci_dev *dev) | ||
1013 | { | ||
1014 | #ifdef CONFIG_PCI_QUIRKS | ||
1015 | int pos; | ||
1016 | u32 header, tmp; | ||
1017 | |||
1018 | pci_read_config_dword(dev, PCI_VENDOR_ID, &header); | ||
1019 | |||
1020 | for (pos = PCI_CFG_SPACE_SIZE; | ||
1021 | pos < PCI_CFG_SPACE_EXP_SIZE; pos += PCI_CFG_SPACE_SIZE) { | ||
1022 | if (pci_read_config_dword(dev, pos, &tmp) != PCIBIOS_SUCCESSFUL | ||
1023 | || header != tmp) | ||
1024 | return false; | ||
1025 | } | ||
1026 | |||
1027 | return true; | ||
1028 | #else | ||
1029 | return false; | ||
1030 | #endif | ||
1031 | } | ||
1032 | |||
1033 | /** | ||
997 | * pci_cfg_space_size - get the configuration space size of the PCI device. | 1034 | * pci_cfg_space_size - get the configuration space size of the PCI device. |
998 | * @dev: PCI device | 1035 | * @dev: PCI device |
999 | * | 1036 | * |
@@ -1011,7 +1048,7 @@ static int pci_cfg_space_size_ext(struct pci_dev *dev) | |||
1011 | 1048 | ||
1012 | if (pci_read_config_dword(dev, pos, &status) != PCIBIOS_SUCCESSFUL) | 1049 | if (pci_read_config_dword(dev, pos, &status) != PCIBIOS_SUCCESSFUL) |
1013 | goto fail; | 1050 | goto fail; |
1014 | if (status == 0xffffffff) | 1051 | if (status == 0xffffffff || pci_ext_cfg_is_aliased(dev)) |
1015 | goto fail; | 1052 | goto fail; |
1016 | 1053 | ||
1017 | return PCI_CFG_SPACE_EXP_SIZE; | 1054 | return PCI_CFG_SPACE_EXP_SIZE; |