aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2012-09-17 22:16:11 -0700
committerYinghai Lu <yinghai@kernel.org>2012-09-17 22:16:11 -0700
commit7028532ea848038e9f9f701e0665c7c8240e2df2 (patch)
tree79f7a088d75d1075708ca7ad44a382e191113a2a
parent7d5edebd935c975ae7401ae25eb72b7f134788b9 (diff)
downloadlinux-yinghai-7028532ea848038e9f9f701e0665c7c8240e2df2.tar.gz
PCI: Add pci_stop_and_remove_root_bus()
It supports both pci root bus and pci bus under pci bridge. -v2: clear pci_bridge's subordinate. -v3: only handle root bus. and also put Jiang's get/put pair in -v4: fold pci_stop/remove_bus_devices in... reducing confusing. Signed-off-by: Yinghai Lu <yinghai@kernel.org>
-rw-r--r--drivers/pci/remove.c40
-rw-r--r--include/linux/pci.h2
2 files changed, 42 insertions, 0 deletions
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 513972f3ed136..4ee528af97fe1 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -111,3 +111,43 @@ void pci_stop_and_remove_bus_device(struct pci_dev *dev)
pci_remove_bus_device(dev);
}
EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
+
+static void pci_stop_host_bridge(struct pci_host_bridge *bridge)
+{
+ device_unregister(&bridge->dev);
+}
+
+void pci_stop_root_bus(struct pci_bus *bus)
+{
+ struct pci_dev *child, *tmp;
+ struct pci_host_bridge *host_bridge;
+
+ if (!pci_is_root_bus(bus))
+ return;
+
+ host_bridge = to_pci_host_bridge(bus->bridge);
+ list_for_each_entry_safe_reverse(child, tmp,
+ &bus->devices, bus_list)
+ pci_stop_bus_device(child);
+ get_device(&host_bridge->dev);
+ pci_stop_host_bridge(host_bridge);
+}
+
+void pci_remove_root_bus(struct pci_bus *bus)
+{
+ struct pci_dev *child, *tmp;
+ struct pci_host_bridge *host_bridge;
+
+ if (!pci_is_root_bus(bus))
+ return;
+
+ host_bridge = to_pci_host_bridge(bus->bridge);
+ list_for_each_entry_safe(child, tmp,
+ &bus->devices, bus_list)
+ pci_remove_bus_device(child);
+ pci_remove_bus(bus);
+ host_bridge->bus = NULL;
+ put_device(&host_bridge->dev);
+}
+
+
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 740407726e079..88ae2373add38 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -735,6 +735,8 @@ extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
extern void pci_dev_put(struct pci_dev *dev);
extern void pci_remove_bus(struct pci_bus *b);
extern void pci_stop_and_remove_bus_device(struct pci_dev *dev);
+void pci_stop_root_bus(struct pci_bus *bus);
+void pci_remove_root_bus(struct pci_bus *bus);
void pci_setup_cardbus(struct pci_bus *bus);
extern void pci_sort_breadthfirst(void);
#define dev_is_pci(d) ((d)->bus == &pci_bus_type)