From 1917dd43bf0413392d644a32b1e6c975fc228135 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 24 Feb 2003 00:27:59 -0800 Subject: [PATCH] PCI: remove check_region abuse (and code duplication) from pci hp code We have a function pci_dev_driver() to check whether a pci_dev has an driver attached to it. It's handling of legacy devices is a bit simpler than what the hotplug code did (duplicated in various places), but if that stuff is really needed the generic code should be updated. --- include/linux/pci.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/pci.h b/include/linux/pci.h index e63da00d4cf6..312606c86074 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -692,7 +692,6 @@ struct pci_visit { extern int pci_visit_dev(struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_parent); -extern int pci_is_dev_in_use(struct pci_dev *dev); extern int pci_remove_device_safe(struct pci_dev *dev); #endif /* CONFIG_PCI */ -- cgit v1.2.3 From e886a0830c104b218c80752dc8465b4c28e75f91 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 24 Feb 2003 00:28:58 -0800 Subject: [PATCH] PCI: Make hot unplugging of PCI buses work Here's the updated patch: - Scott spotted a leak my handling of procfs wrt buses. - I've also killed pci_remove_device() entirely - it is now inlined. - After one of Alan's mails, I decided that pci_remove_behind_bridge() is a much better name than pci_remove_all_bus_devices() --- drivers/pci/hotplug.c | 63 +++++++++++++++++++++++++++++++++++++++++++++------ include/linux/pci.h | 3 ++- 2 files changed, 58 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c index 33b7e9e5336d..26eaf74c4483 100644 --- a/drivers/pci/hotplug.c +++ b/drivers/pci/hotplug.c @@ -10,6 +10,7 @@ #define DBG(x...) #endif +static void pci_free_resources(struct pci_dev *dev); #ifdef CONFIG_HOTPLUG int pci_hotplug (struct device *dev, char **envp, int num_envp, @@ -185,7 +186,13 @@ int pci_remove_device_safe(struct pci_dev *dev) { if (pci_dev_driver(dev)) return -EBUSY; - pci_remove_device(dev); + device_unregister(&dev->dev); + list_del(&dev->bus_list); + list_del(&dev->global_list); + pci_free_resources(dev); +#ifdef CONFIG_PROC_FS + pci_proc_detach_device(dev); +#endif return 0; } EXPORT_SYMBOL(pci_remove_device_safe); @@ -233,15 +240,33 @@ pci_free_resources(struct pci_dev *dev) } /** - * pci_remove_device - remove a pci device + * pci_remove_bus_device - remove a PCI device and any children * @dev: the device to remove * - * Delete the device structure from the device lists, - * remove the /proc entry, and notify userspace (/sbin/hotplug). + * Remove a PCI device from the device lists, informing the drivers + * that the device has been removed. We also remove any subordinate + * buses and children in a depth-first manner. + * + * For each device we remove, delete the device structure from the + * device lists, remove the /proc entry, and notify userspace + * (/sbin/hotplug). */ -void -pci_remove_device(struct pci_dev *dev) +void pci_remove_bus_device(struct pci_dev *dev) { + if (dev->subordinate) { + struct pci_bus *b = dev->subordinate; + + pci_remove_behind_bridge(dev); + +#ifdef CONFIG_PROC_FS + pci_proc_detach_bus(b); +#endif + + list_del(&b->node); + kfree(b); + dev->subordinate = NULL; + } + device_unregister(&dev->dev); list_del(&dev->bus_list); list_del(&dev->global_list); @@ -249,9 +274,33 @@ pci_remove_device(struct pci_dev *dev) #ifdef CONFIG_PROC_FS pci_proc_detach_device(dev); #endif + + kfree(dev); +} + +/** + * pci_remove_behind_bridge - 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) +{ + struct list_head *l, *n; + + if (dev->subordinate) { + list_for_each_safe(l, n, &dev->subordinate->devices) { + struct pci_dev *dev = pci_dev_b(l); + + pci_remove_bus_device(dev); + } + } } #ifdef CONFIG_HOTPLUG EXPORT_SYMBOL(pci_insert_device); -EXPORT_SYMBOL(pci_remove_device); +EXPORT_SYMBOL(pci_remove_bus_device); +EXPORT_SYMBOL(pci_remove_behind_bridge); #endif diff --git a/include/linux/pci.h b/include/linux/pci.h index 312606c86074..402a5e0a7c52 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -645,7 +645,8 @@ void pci_release_region(struct pci_dev *, int); int pci_register_driver(struct pci_driver *); void pci_unregister_driver(struct pci_driver *); void pci_insert_device(struct pci_dev *, struct pci_bus *); -void pci_remove_device(struct pci_dev *); +void pci_remove_bus_device(struct pci_dev *); +void pci_remove_behind_bridge(struct pci_dev *); struct pci_driver *pci_dev_driver(const struct pci_dev *); const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev); unsigned int pci_do_scan_bus(struct pci_bus *bus); -- cgit v1.2.3