summaryrefslogtreecommitdiff
path: root/drivers/pci/access.c
diff options
context:
space:
mode:
authorKeith Busch <keith.busch@intel.com>2017-03-29 22:49:06 -0500
committerBjorn Helgaas <bhelgaas@google.com>2017-03-29 22:54:56 -0500
commit4b103883473964bbb7b0b6934999b283ee234a8a (patch)
treec03775e34f887f26d6f5eeb839006614033f2cf4 /drivers/pci/access.c
parent89ee9f7680031d7df91a1a27abac69e034c2e892 (diff)
downloadlinux-4b103883473964bbb7b0b6934999b283ee234a8a.tar.gz
PCI: Don't attempt config access to disconnected devices
If we've detected the PCI device is disconnected, there is no need to attempt to access its config space since we know the operation will fail. Make all the config reads and writes return -ENODEV error immediately when in such a state. If a caller requests a config read to a disconnected device, return a data value of all 1's. This is the same as what hardware is expected to return when accessing a removed device, but software can do this faster without relying on hardware. Tested-by: Krishna Dhulipala <krishnad@fb.com> Signed-off-by: Keith Busch <keith.busch@intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Wei Zhang <wzhang@fb.com>
Diffstat (limited to 'drivers/pci/access.c')
-rw-r--r--drivers/pci/access.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index c70e3113df7a..1c8051003e67 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -893,12 +893,20 @@ EXPORT_SYMBOL(pcie_capability_clear_and_set_dword);
int pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val)
{
+ if (pci_dev_is_disconnected(dev)) {
+ *val = ~0;
+ return -ENODEV;
+ }
return pci_bus_read_config_byte(dev->bus, dev->devfn, where, val);
}
EXPORT_SYMBOL(pci_read_config_byte);
int pci_read_config_word(const struct pci_dev *dev, int where, u16 *val)
{
+ if (pci_dev_is_disconnected(dev)) {
+ *val = ~0;
+ return -ENODEV;
+ }
return pci_bus_read_config_word(dev->bus, dev->devfn, where, val);
}
EXPORT_SYMBOL(pci_read_config_word);
@@ -906,18 +914,26 @@ EXPORT_SYMBOL(pci_read_config_word);
int pci_read_config_dword(const struct pci_dev *dev, int where,
u32 *val)
{
+ if (pci_dev_is_disconnected(dev)) {
+ *val = ~0;
+ return -ENODEV;
+ }
return pci_bus_read_config_dword(dev->bus, dev->devfn, where, val);
}
EXPORT_SYMBOL(pci_read_config_dword);
int pci_write_config_byte(const struct pci_dev *dev, int where, u8 val)
{
+ if (pci_dev_is_disconnected(dev))
+ return -ENODEV;
return pci_bus_write_config_byte(dev->bus, dev->devfn, where, val);
}
EXPORT_SYMBOL(pci_write_config_byte);
int pci_write_config_word(const struct pci_dev *dev, int where, u16 val)
{
+ if (pci_dev_is_disconnected(dev))
+ return -ENODEV;
return pci_bus_write_config_word(dev->bus, dev->devfn, where, val);
}
EXPORT_SYMBOL(pci_write_config_word);
@@ -925,6 +941,8 @@ EXPORT_SYMBOL(pci_write_config_word);
int pci_write_config_dword(const struct pci_dev *dev, int where,
u32 val)
{
+ if (pci_dev_is_disconnected(dev))
+ return -ENODEV;
return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val);
}
EXPORT_SYMBOL(pci_write_config_dword);