summaryrefslogtreecommitdiff
path: root/drivers/pci/hotplug/pciehp_pci.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-01-14 12:03:14 -0700
committerBjorn Helgaas <bhelgaas@google.com>2014-01-14 12:14:25 -0700
commitc4ec84c7db0e4b01ed40cc2388f16ae5c6513cc0 (patch)
treeb280cdcdbf714b6709e8d87a0d157f4979cb73d7 /drivers/pci/hotplug/pciehp_pci.c
parent5ef68e8867ca9d979644d05c6045b2c79d8989de (diff)
PCI: hotplug: Use global PCI rescan-remove locking
Multiple race conditions are possible between PCI hotplug and the generic PCI bus rescan and device removal that can be triggered via sysfs. To avoid those race conditions make PCI hotplug use global PCI rescan-remove locking. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci/hotplug/pciehp_pci.c')
-rw-r--r--drivers/pci/hotplug/pciehp_pci.c17
1 files changed, 13 insertions, 4 deletions
diff --git a/drivers/pci/hotplug/pciehp_pci.c b/drivers/pci/hotplug/pciehp_pci.c
index 198355112ee7..b07d7cc2d697 100644
--- a/drivers/pci/hotplug/pciehp_pci.c
+++ b/drivers/pci/hotplug/pciehp_pci.c
@@ -39,22 +39,26 @@ int pciehp_configure_device(struct slot *p_slot)
struct pci_dev *dev;
struct pci_dev *bridge = p_slot->ctrl->pcie->port;
struct pci_bus *parent = bridge->subordinate;
- int num;
+ int num, ret = 0;
struct controller *ctrl = p_slot->ctrl;
+ pci_lock_rescan_remove();
+
dev = pci_get_slot(parent, PCI_DEVFN(0, 0));
if (dev) {
ctrl_err(ctrl, "Device %s already exists "
"at %04x:%02x:00, cannot hot-add\n", pci_name(dev),
pci_domain_nr(parent), parent->number);
pci_dev_put(dev);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
num = pci_scan_slot(parent, PCI_DEVFN(0, 0));
if (num == 0) {
ctrl_err(ctrl, "No new device found\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto out;
}
list_for_each_entry(dev, &parent->devices, bus_list)
@@ -73,7 +77,9 @@ int pciehp_configure_device(struct slot *p_slot)
pci_bus_add_devices(parent);
- return 0;
+ out:
+ pci_unlock_rescan_remove();
+ return ret;
}
int pciehp_unconfigure_device(struct slot *p_slot)
@@ -90,6 +96,8 @@ int pciehp_unconfigure_device(struct slot *p_slot)
__func__, pci_domain_nr(parent), parent->number);
pciehp_get_adapter_status(p_slot, &presence);
+ pci_lock_rescan_remove();
+
/*
* Stopping an SR-IOV PF device removes all the associated VFs,
* which will update the bus->devices list and confuse the
@@ -124,5 +132,6 @@ int pciehp_unconfigure_device(struct slot *p_slot)
pci_dev_put(dev);
}
+ pci_unlock_rescan_remove();
return rc;
}