diff options
author | Yunhong Jiang <yunhong.jiang@intel.com> | 2015-08-04 12:17:53 -0700 |
---|---|---|
committer | Yunhong Jiang <yunhong.jiang@intel.com> | 2015-08-04 15:44:42 -0700 |
commit | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (patch) | |
tree | 1c9cafbcd35f783a87880a10f85d1a060db1a563 /kernel/drivers/pci/remove.c | |
parent | 98260f3884f4a202f9ca5eabed40b1354c489b29 (diff) |
Add the rt linux 4.1.3-rt3 as base
Import the rt linux 4.1.3-rt3 as OPNFV kvm base.
It's from git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git linux-4.1.y-rt and
the base is:
commit 0917f823c59692d751951bf5ea699a2d1e2f26a2
Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Date: Sat Jul 25 12:13:34 2015 +0200
Prepare v4.1.3-rt3
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
We lose all the git history this way and it's not good. We
should apply another opnfv project repo in future.
Change-Id: I87543d81c9df70d99c5001fbdf646b202c19f423
Signed-off-by: Yunhong Jiang <yunhong.jiang@intel.com>
Diffstat (limited to 'kernel/drivers/pci/remove.c')
-rw-r--r-- | kernel/drivers/pci/remove.c | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/kernel/drivers/pci/remove.c b/kernel/drivers/pci/remove.c new file mode 100644 index 000000000..8a280e9c2 --- /dev/null +++ b/kernel/drivers/pci/remove.c @@ -0,0 +1,162 @@ +#include <linux/pci.h> +#include <linux/module.h> +#include <linux/pci-aspm.h> +#include "pci.h" + +static void pci_free_resources(struct pci_dev *dev) +{ + int i; + + pci_cleanup_rom(dev); + for (i = 0; i < PCI_NUM_RESOURCES; i++) { + struct resource *res = dev->resource + i; + if (res->parent) + release_resource(res); + } +} + +static void pci_stop_dev(struct pci_dev *dev) +{ + pci_pme_active(dev, false); + + if (dev->is_added) { + pci_proc_detach_device(dev); + pci_remove_sysfs_dev_files(dev); + device_release_driver(&dev->dev); + dev->is_added = 0; + } + + if (dev->bus->self) + pcie_aspm_exit_link_state(dev); +} + +static void pci_destroy_dev(struct pci_dev *dev) +{ + if (!dev->dev.kobj.parent) + return; + + device_del(&dev->dev); + + down_write(&pci_bus_sem); + list_del(&dev->bus_list); + up_write(&pci_bus_sem); + + pci_free_resources(dev); + put_device(&dev->dev); +} + +void pci_remove_bus(struct pci_bus *bus) +{ + pci_proc_detach_bus(bus); + + down_write(&pci_bus_sem); + list_del(&bus->node); + pci_bus_release_busn_res(bus); + up_write(&pci_bus_sem); + pci_remove_legacy_files(bus); + pcibios_remove_bus(bus); + device_unregister(&bus->dev); +} +EXPORT_SYMBOL(pci_remove_bus); + +static void pci_stop_bus_device(struct pci_dev *dev) +{ + struct pci_bus *bus = dev->subordinate; + struct pci_dev *child, *tmp; + + /* + * Stopping an SR-IOV PF device removes all the associated VFs, + * which will update the bus->devices list and confuse the + * iterator. Therefore, iterate in reverse so we remove the VFs + * first, then the PF. + */ + if (bus) { + list_for_each_entry_safe_reverse(child, tmp, + &bus->devices, bus_list) + pci_stop_bus_device(child); + } + + pci_stop_dev(dev); +} + +static void pci_remove_bus_device(struct pci_dev *dev) +{ + struct pci_bus *bus = dev->subordinate; + struct pci_dev *child, *tmp; + + if (bus) { + list_for_each_entry_safe(child, tmp, + &bus->devices, bus_list) + pci_remove_bus_device(child); + + pci_remove_bus(bus); + dev->subordinate = NULL; + } + + pci_destroy_dev(dev); +} + +/** + * pci_stop_and_remove_bus_device - remove a PCI device and any children + * @dev: the device to remove + * + * 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_stop_and_remove_bus_device(struct pci_dev *dev) +{ + pci_stop_bus_device(dev); + pci_remove_bus_device(dev); +} +EXPORT_SYMBOL(pci_stop_and_remove_bus_device); + +void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev) +{ + pci_lock_rescan_remove(); + pci_stop_and_remove_bus_device(dev); + pci_unlock_rescan_remove(); +} +EXPORT_SYMBOL_GPL(pci_stop_and_remove_bus_device_locked); + +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); + + /* stop the host bridge */ + device_release_driver(&host_bridge->dev); +} +EXPORT_SYMBOL_GPL(pci_stop_root_bus); + +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; + + /* remove the host bridge */ + device_unregister(&host_bridge->dev); +} +EXPORT_SYMBOL_GPL(pci_remove_root_bus); |