diff options
Diffstat (limited to 'drivers/pci/remove.c')
| -rw-r--r-- | drivers/pci/remove.c | 27 | 
1 files changed, 19 insertions, 8 deletions
| diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index ef8b18c48f26..fd77e2bde2e8 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -79,7 +79,7 @@ EXPORT_SYMBOL(pci_remove_bus);  static void __pci_remove_behind_bridge(struct pci_dev *dev);  /** - * pci_remove_bus_device - remove a PCI device and any children + * 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 @@ -90,7 +90,7 @@ static void __pci_remove_behind_bridge(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) +void __pci_remove_bus_device(struct pci_dev *dev)  {  	if (dev->subordinate) {  		struct pci_bus *b = dev->subordinate; @@ -102,7 +102,9 @@ static void __pci_remove_bus_device(struct pci_dev *dev)  	pci_destroy_dev(dev);  } -void pci_remove_bus_device(struct pci_dev *dev) +EXPORT_SYMBOL(__pci_remove_bus_device); + +void pci_stop_and_remove_bus_device(struct pci_dev *dev)  {  	pci_stop_bus_device(dev);  	__pci_remove_bus_device(dev); @@ -127,14 +129,15 @@ static void pci_stop_behind_bridge(struct pci_dev *dev)  }  /** - * pci_remove_behind_bridge - remove all devices behind a PCI bridge + * pci_stop_and_remove_behind_bridge - stop and remove all devices behind + *					 a PCI bridge   * @dev: PCI bridge device   *   * Remove all devices on the bus, except for the parent bridge.   * This also removes any child buses, and any devices they may   * contain in a depth-first manner.   */ -void pci_remove_behind_bridge(struct pci_dev *dev) +void pci_stop_and_remove_behind_bridge(struct pci_dev *dev)  {  	pci_stop_behind_bridge(dev);  	__pci_remove_behind_bridge(dev); @@ -144,7 +147,15 @@ static void pci_stop_bus_devices(struct pci_bus *bus)  {  	struct list_head *l, *n; -	list_for_each_safe(l, n, &bus->devices) { +	/* +	 * 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_prev_safe(l, n, &bus->devices) {  		struct pci_dev *dev = pci_dev_b(l);  		pci_stop_bus_device(dev);  	} @@ -166,6 +177,6 @@ void pci_stop_bus_device(struct pci_dev *dev)  	pci_stop_dev(dev);  } -EXPORT_SYMBOL(pci_remove_bus_device); -EXPORT_SYMBOL(pci_remove_behind_bridge); +EXPORT_SYMBOL(pci_stop_and_remove_bus_device); +EXPORT_SYMBOL(pci_stop_and_remove_behind_bridge);  EXPORT_SYMBOL_GPL(pci_stop_bus_device); | 
