diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2012-08-17 17:25:01 (GMT) |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-08-22 17:31:42 (GMT) |
commit | 2ed168eeb3edec029aa0eca5cb981d6376f931f9 (patch) | |
tree | 015c0c9f116b9e8f246784b7f0ba71970df81e58 | |
parent | 66455f5472383df3632140e04f0852215e5c9ce8 (diff) | |
download | linux-2ed168eeb3edec029aa0eca5cb981d6376f931f9.tar.xz |
PCI: Fold stop and remove helpers into their callers
pci_stop_bus_devices() is only two lines of code and is only called by
pci_stop_bus_device(), so I think it's easier to read if we just fold it
into the caller. Similarly for __pci_remove_behind_bridge().
Tested-by: Yijing Wang <wangyijing@huawei.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Yinghai Lu <yinghai@kernel.org>
-rw-r--r-- | drivers/pci/remove.c | 53 |
1 files changed, 20 insertions, 33 deletions
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index f17a027..30d002e 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -78,7 +78,6 @@ void pci_remove_bus(struct pci_bus *pci_bus) } EXPORT_SYMBOL(pci_remove_bus); -static void __pci_remove_behind_bridge(struct pci_dev *dev); static void pci_stop_bus_device(struct pci_dev *dev); /** @@ -95,11 +94,14 @@ static void pci_stop_bus_device(struct pci_dev *dev); */ static void __pci_remove_bus_device(struct pci_dev *dev) { - if (dev->subordinate) { - struct pci_bus *b = dev->subordinate; + 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_behind_bridge(dev); - pci_remove_bus(b); + pci_remove_bus(bus); dev->subordinate = NULL; } @@ -112,32 +114,6 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev) __pci_remove_bus_device(dev); } -static void __pci_remove_behind_bridge(struct pci_dev *dev) -{ - struct pci_dev *child, *tmp; - - if (dev->subordinate) - list_for_each_entry_safe(child, tmp, - &dev->subordinate->devices, bus_list) - __pci_remove_bus_device(child); -} - -static void pci_stop_bus_devices(struct pci_bus *bus) -{ - struct pci_dev *dev, *tmp; - - /* - * VFs could be removed by pci_stop_and_remove_bus_device() in the - * pci_stop_bus_devices() code path for PF. - * aka, bus->devices get updated in the process. - * but VFs are inserted after PFs when SRIOV is enabled for PF, - * We can iterate the list backwards to get prev valid PF instead - * of removed VF. - */ - list_for_each_entry_safe_reverse(dev, tmp, &bus->devices, bus_list) - pci_stop_bus_device(dev); -} - /** * pci_stop_bus_device - stop a PCI device and any children * @dev: the device to stop @@ -148,8 +124,19 @@ static void pci_stop_bus_devices(struct pci_bus *bus) */ static void pci_stop_bus_device(struct pci_dev *dev) { - if (dev->subordinate) - pci_stop_bus_devices(dev->subordinate); + struct pci_bus *bus = dev->subordinate; + struct pci_dev *child, *tmp; + + /* + * Removing an SR-IOV PF device removes all the associated VFs, + * which will update the bus->devices list and confuse the + * iterator. Therefore, iterate in reverse so we remove the VFs + * first, then the PF. + */ + if (bus) + list_for_each_entry_safe_reverse(child, tmp, + &bus->devices, bus_list) + pci_stop_bus_device(child); pci_stop_dev(dev); } |