aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/remove.c
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2012-08-17 13:25:01 -0400
committerBjorn Helgaas <bhelgaas@google.com>2012-08-22 13:31:42 -0400
commit2ed168eeb3edec029aa0eca5cb981d6376f931f9 (patch)
tree015c0c9f116b9e8f246784b7f0ba71970df81e58 /drivers/pci/remove.c
parent66455f5472383df3632140e04f0852215e5c9ce8 (diff)
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>
Diffstat (limited to 'drivers/pci/remove.c')
-rw-r--r--drivers/pci/remove.c53
1 files changed, 20 insertions, 33 deletions
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index f17a02781e67..30d002e83e2d 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -78,7 +78,6 @@ void pci_remove_bus(struct pci_bus *pci_bus)
78} 78}
79EXPORT_SYMBOL(pci_remove_bus); 79EXPORT_SYMBOL(pci_remove_bus);
80 80
81static void __pci_remove_behind_bridge(struct pci_dev *dev);
82static void pci_stop_bus_device(struct pci_dev *dev); 81static void pci_stop_bus_device(struct pci_dev *dev);
83 82
84/** 83/**
@@ -95,11 +94,14 @@ static void pci_stop_bus_device(struct pci_dev *dev);
95 */ 94 */
96static void __pci_remove_bus_device(struct pci_dev *dev) 95static void __pci_remove_bus_device(struct pci_dev *dev)
97{ 96{
98 if (dev->subordinate) { 97 struct pci_bus *bus = dev->subordinate;
99 struct pci_bus *b = dev->subordinate; 98 struct pci_dev *child, *tmp;
99
100 if (bus) {
101 list_for_each_entry_safe(child, tmp, &bus->devices, bus_list)
102 __pci_remove_bus_device(child);
100 103
101 __pci_remove_behind_bridge(dev); 104 pci_remove_bus(bus);
102 pci_remove_bus(b);
103 dev->subordinate = NULL; 105 dev->subordinate = NULL;
104 } 106 }
105 107
@@ -112,32 +114,6 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev)
112 __pci_remove_bus_device(dev); 114 __pci_remove_bus_device(dev);
113} 115}
114 116
115static void __pci_remove_behind_bridge(struct pci_dev *dev)
116{
117 struct pci_dev *child, *tmp;
118
119 if (dev->subordinate)
120 list_for_each_entry_safe(child, tmp,
121 &dev->subordinate->devices, bus_list)
122 __pci_remove_bus_device(child);
123}
124
125static void pci_stop_bus_devices(struct pci_bus *bus)
126{
127 struct pci_dev *dev, *tmp;
128
129 /*
130 * VFs could be removed by pci_stop_and_remove_bus_device() in the
131 * pci_stop_bus_devices() code path for PF.
132 * aka, bus->devices get updated in the process.
133 * but VFs are inserted after PFs when SRIOV is enabled for PF,
134 * We can iterate the list backwards to get prev valid PF instead
135 * of removed VF.
136 */
137 list_for_each_entry_safe_reverse(dev, tmp, &bus->devices, bus_list)
138 pci_stop_bus_device(dev);
139}
140
141/** 117/**
142 * pci_stop_bus_device - stop a PCI device and any children 118 * pci_stop_bus_device - stop a PCI device and any children
143 * @dev: the device to stop 119 * @dev: the device to stop
@@ -148,8 +124,19 @@ static void pci_stop_bus_devices(struct pci_bus *bus)
148 */ 124 */
149static void pci_stop_bus_device(struct pci_dev *dev) 125static void pci_stop_bus_device(struct pci_dev *dev)
150{ 126{
151 if (dev->subordinate) 127 struct pci_bus *bus = dev->subordinate;
152 pci_stop_bus_devices(dev->subordinate); 128 struct pci_dev *child, *tmp;
129
130 /*
131 * Removing an SR-IOV PF device removes all the associated VFs,
132 * which will update the bus->devices list and confuse the
133 * iterator. Therefore, iterate in reverse so we remove the VFs
134 * first, then the PF.
135 */
136 if (bus)
137 list_for_each_entry_safe_reverse(child, tmp,
138 &bus->devices, bus_list)
139 pci_stop_bus_device(child);
153 140
154 pci_stop_dev(dev); 141 pci_stop_dev(dev);
155} 142}