diff options
author | Yinghai Lu <yinghai@kernel.org> | 2012-09-17 22:16:11 -0700 |
---|---|---|
committer | Yinghai Lu <yinghai@kernel.org> | 2012-09-17 22:16:11 -0700 |
commit | 7028532ea848038e9f9f701e0665c7c8240e2df2 (patch) | |
tree | 79f7a088d75d1075708ca7ad44a382e191113a2a | |
parent | 7d5edebd935c975ae7401ae25eb72b7f134788b9 (diff) | |
download | linux-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.c | 40 | ||||
-rw-r--r-- | include/linux/pci.h | 2 |
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) |