diff options
author | Yinghai Lu <yinghai@kernel.org> | 2012-09-19 14:54:20 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2012-09-20 19:37:23 -0400 |
commit | 3891b6acb4f443cbe2e99367ee5e67c6bc29d446 (patch) | |
tree | 31f19d4d3ca748c526e0bb82a670613c6c71ca40 /drivers/pci/remove.c | |
parent | 94bb346480f8646871e5547491b5746ae0a643c3 (diff) |
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>
Diffstat (limited to 'drivers/pci/remove.c')
-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 4f9ca9162895..513972f3ed13 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c | |||
@@ -56,25 +56,13 @@ void pci_remove_bus(struct pci_bus *bus) | |||
56 | } | 56 | } |
57 | EXPORT_SYMBOL(pci_remove_bus); | 57 | EXPORT_SYMBOL(pci_remove_bus); |
58 | 58 | ||
59 | /** | 59 | static void pci_stop_bus_device(struct pci_dev *dev) |
60 | * pci_stop_and_remove_bus_device - remove a PCI device and any children | ||
61 | * @dev: the device to remove | ||
62 | * | ||
63 | * Remove a PCI device from the device lists, informing the drivers | ||
64 | * that the device has been removed. We also remove any subordinate | ||
65 | * buses and children in a depth-first manner. | ||
66 | * | ||
67 | * For each device we remove, delete the device structure from the | ||
68 | * device lists, remove the /proc entry, and notify userspace | ||
69 | * (/sbin/hotplug). | ||
70 | */ | ||
71 | void pci_stop_and_remove_bus_device(struct pci_dev *dev) | ||
72 | { | 60 | { |
73 | struct pci_bus *bus = dev->subordinate; | 61 | struct pci_bus *bus = dev->subordinate; |
74 | struct pci_dev *child, *tmp; | 62 | struct pci_dev *child, *tmp; |
75 | 63 | ||
76 | /* | 64 | /* |
77 | * Removing an SR-IOV PF device removes all the associated VFs, | 65 | * Stopping an SR-IOV PF device removes all the associated VFs, |
78 | * which will update the bus->devices list and confuse the | 66 | * which will update the bus->devices list and confuse the |
79 | * iterator. Therefore, iterate in reverse so we remove the VFs | 67 | * iterator. Therefore, iterate in reverse so we remove the VFs |
80 | * first, then the PF. | 68 | * first, then the PF. |
@@ -82,13 +70,44 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev) | |||
82 | if (bus) { | 70 | if (bus) { |
83 | list_for_each_entry_safe_reverse(child, tmp, | 71 | list_for_each_entry_safe_reverse(child, tmp, |
84 | &bus->devices, bus_list) | 72 | &bus->devices, bus_list) |
85 | pci_stop_and_remove_bus_device(child); | 73 | pci_stop_bus_device(child); |
74 | } | ||
75 | |||
76 | pci_stop_dev(dev); | ||
77 | } | ||
78 | |||
79 | static void pci_remove_bus_device(struct pci_dev *dev) | ||
80 | { | ||
81 | struct pci_bus *bus = dev->subordinate; | ||
82 | struct pci_dev *child, *tmp; | ||
83 | |||
84 | if (bus) { | ||
85 | list_for_each_entry_safe(child, tmp, | ||
86 | &bus->devices, bus_list) | ||
87 | pci_remove_bus_device(child); | ||
86 | 88 | ||
87 | pci_remove_bus(bus); | 89 | pci_remove_bus(bus); |
88 | dev->subordinate = NULL; | 90 | dev->subordinate = NULL; |
89 | } | 91 | } |
90 | 92 | ||
91 | pci_stop_dev(dev); | ||
92 | pci_destroy_dev(dev); | 93 | pci_destroy_dev(dev); |
93 | } | 94 | } |
95 | |||
96 | /** | ||
97 | * pci_stop_and_remove_bus_device - remove a PCI device and any children | ||
98 | * @dev: the device to remove | ||
99 | * | ||
100 | * Remove a PCI device from the device lists, informing the drivers | ||
101 | * that the device has been removed. We also remove any subordinate | ||
102 | * buses and children in a depth-first manner. | ||
103 | * | ||
104 | * For each device we remove, delete the device structure from the | ||
105 | * device lists, remove the /proc entry, and notify userspace | ||
106 | * (/sbin/hotplug). | ||
107 | */ | ||
108 | void pci_stop_and_remove_bus_device(struct pci_dev *dev) | ||
109 | { | ||
110 | pci_stop_bus_device(dev); | ||
111 | pci_remove_bus_device(dev); | ||
112 | } | ||
94 | EXPORT_SYMBOL(pci_stop_and_remove_bus_device); | 113 | EXPORT_SYMBOL(pci_stop_and_remove_bus_device); |