summaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2012-08-17 11:57:48 -0600
committerBjorn Helgaas <bhelgaas@google.com>2012-08-22 11:31:48 -0600
commit282e1d655fe7c7c2e6b0dd8166c4c6b7c2a1219b (patch)
tree9890411229a7f8b7314ddbf44e33554fa1b360b8 /drivers/pci
parent2ed168eeb3edec029aa0eca5cb981d6376f931f9 (diff)
downloadlinux-282e1d655fe7c7c2e6b0dd8166c4c6b7c2a1219b.tar.bz2
PCI: Stop and remove devices in one pass
Previously, when we removed a PCI device, we made two passes over the hierarchy rooted at the device. In the first pass, we stopped all the devices, and in the second, we removed them. This patch combines the two passes into one so that we remove a device as soon as it and all its children have been stopped. Note that we previously stopped devices in reverse order and removed them in forward order. Now we stop and remove them in reverse order. Tested-by: Yijing Wang <wangyijing@huawei.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: Yinghai Lu <yinghai@kernel.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/remove.c42
1 files changed, 7 insertions, 35 deletions
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 30d002e83e2d..38281042c31c 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -78,8 +78,6 @@ void pci_remove_bus(struct pci_bus *pci_bus)
}
EXPORT_SYMBOL(pci_remove_bus);
-static void pci_stop_bus_device(struct pci_dev *dev);
-
/**
* pci_stop_and_remove_bus_device - remove a PCI device and any children
* @dev: the device to remove
@@ -92,38 +90,8 @@ static void pci_stop_bus_device(struct pci_dev *dev);
* device lists, remove the /proc entry, and notify userspace
* (/sbin/hotplug).
*/
-static void __pci_remove_bus_device(struct pci_dev *dev)
-{
- struct pci_bus *bus = dev->subordinate;
- struct pci_dev *child, *tmp;
-
- if (bus) {
- list_for_each_entry_safe(child, tmp, &bus->devices, bus_list)
- __pci_remove_bus_device(child);
-
- pci_remove_bus(bus);
- dev->subordinate = NULL;
- }
-
- pci_destroy_dev(dev);
-}
-
void pci_stop_and_remove_bus_device(struct pci_dev *dev)
{
- pci_stop_bus_device(dev);
- __pci_remove_bus_device(dev);
-}
-
-/**
- * pci_stop_bus_device - stop a PCI device and any children
- * @dev: the device to stop
- *
- * Stop a PCI device (detach the driver, remove from the global list
- * and so on). This also stop any subordinate buses and children in a
- * depth-first manner.
- */
-static void pci_stop_bus_device(struct pci_dev *dev)
-{
struct pci_bus *bus = dev->subordinate;
struct pci_dev *child, *tmp;
@@ -133,12 +101,16 @@ static void pci_stop_bus_device(struct pci_dev *dev)
* iterator. Therefore, iterate in reverse so we remove the VFs
* first, then the PF.
*/
- if (bus)
+ if (bus) {
list_for_each_entry_safe_reverse(child, tmp,
&bus->devices, bus_list)
- pci_stop_bus_device(child);
+ pci_stop_and_remove_bus_device(child);
+
+ pci_remove_bus(bus);
+ dev->subordinate = NULL;
+ }
pci_stop_dev(dev);
+ pci_destroy_dev(dev);
}
-
EXPORT_SYMBOL(pci_stop_and_remove_bus_device);