diff options
| author | Yinghai Lu <yinghai@kernel.org> | 2012-09-19 11:54:20 -0700 | 
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-09-20 17:37:23 -0600 | 
| commit | 3891b6acb4f443cbe2e99367ee5e67c6bc29d446 (patch) | |
| tree | 31f19d4d3ca748c526e0bb82a670613c6c71ca40 | |
| parent | 94bb346480f8646871e5547491b5746ae0a643c3 (diff) | |
| download | olio-linux-3.10-3891b6acb4f443cbe2e99367ee5e67c6bc29d446.tar.xz olio-linux-3.10-3891b6acb4f443cbe2e99367ee5e67c6bc29d446.zip  | |
PCI: Stop all children first, before removing all children
This restores the previous behavior of stopping all child devices before
removing any of them.  The current SR-IOV design, where removing the PF
also drops references on all the VFs, depends on having the VFs continue
to exist after having been stopped.
[bhelgaas: changelog]
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
| -rw-r--r-- | drivers/pci/remove.c | 51 | 
1 files changed, 35 insertions, 16 deletions
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index 4f9ca916289..513972f3ed1 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -56,25 +56,13 @@ void pci_remove_bus(struct pci_bus *bus)  }  EXPORT_SYMBOL(pci_remove_bus); -/** - * pci_stop_and_remove_bus_device - remove a PCI device and any children - * @dev: the device to remove - * - * Remove a PCI device from the device lists, informing the drivers - * that the device has been removed.  We also remove any subordinate - * buses and children in a depth-first manner. - * - * For each device we remove, delete the device structure from the - * device lists, remove the /proc entry, and notify userspace - * (/sbin/hotplug). - */ -void pci_stop_and_remove_bus_device(struct pci_dev *dev) +static void pci_stop_bus_device(struct pci_dev *dev)  {  	struct pci_bus *bus = dev->subordinate;  	struct pci_dev *child, *tmp;  	/* -	 * Removing an SR-IOV PF device removes all the associated VFs, +	 * Stopping 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. @@ -82,13 +70,44 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev)  	if (bus) {  		list_for_each_entry_safe_reverse(child, tmp,  						 &bus->devices, bus_list) -			pci_stop_and_remove_bus_device(child); +			pci_stop_bus_device(child); +	} + +	pci_stop_dev(dev); +} + +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_stop_dev(dev);  	pci_destroy_dev(dev);  } + +/** + * pci_stop_and_remove_bus_device - remove a PCI device and any children + * @dev: the device to remove + * + * Remove a PCI device from the device lists, informing the drivers + * that the device has been removed.  We also remove any subordinate + * buses and children in a depth-first manner. + * + * For each device we remove, delete the device structure from the + * device lists, remove the /proc entry, and notify userspace + * (/sbin/hotplug). + */ +void pci_stop_and_remove_bus_device(struct pci_dev *dev) +{ +	pci_stop_bus_device(dev); +	pci_remove_bus_device(dev); +}  EXPORT_SYMBOL(pci_stop_and_remove_bus_device);  |