Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/pci.h>
0003 #include <linux/module.h>
0004 #include "pci.h"
0005 
0006 static void pci_free_resources(struct pci_dev *dev)
0007 {
0008     int i;
0009 
0010     for (i = 0; i < PCI_NUM_RESOURCES; i++) {
0011         struct resource *res = dev->resource + i;
0012         if (res->parent)
0013             release_resource(res);
0014     }
0015 }
0016 
0017 static void pci_stop_dev(struct pci_dev *dev)
0018 {
0019     pci_pme_active(dev, false);
0020 
0021     if (pci_dev_is_added(dev)) {
0022 
0023         device_release_driver(&dev->dev);
0024         pci_proc_detach_device(dev);
0025         pci_remove_sysfs_dev_files(dev);
0026 
0027         pci_dev_assign_added(dev, false);
0028     }
0029 }
0030 
0031 static void pci_destroy_dev(struct pci_dev *dev)
0032 {
0033     if (!dev->dev.kobj.parent)
0034         return;
0035 
0036     device_del(&dev->dev);
0037 
0038     down_write(&pci_bus_sem);
0039     list_del(&dev->bus_list);
0040     up_write(&pci_bus_sem);
0041 
0042     pcie_aspm_exit_link_state(dev);
0043     pci_bridge_d3_update(dev);
0044     pci_free_resources(dev);
0045     put_device(&dev->dev);
0046 }
0047 
0048 void pci_remove_bus(struct pci_bus *bus)
0049 {
0050     pci_proc_detach_bus(bus);
0051 
0052     down_write(&pci_bus_sem);
0053     list_del(&bus->node);
0054     pci_bus_release_busn_res(bus);
0055     up_write(&pci_bus_sem);
0056     pci_remove_legacy_files(bus);
0057 
0058     if (bus->ops->remove_bus)
0059         bus->ops->remove_bus(bus);
0060 
0061     pcibios_remove_bus(bus);
0062     device_unregister(&bus->dev);
0063 }
0064 EXPORT_SYMBOL(pci_remove_bus);
0065 
0066 static void pci_stop_bus_device(struct pci_dev *dev)
0067 {
0068     struct pci_bus *bus = dev->subordinate;
0069     struct pci_dev *child, *tmp;
0070 
0071     /*
0072      * Stopping an SR-IOV PF device removes all the associated VFs,
0073      * which will update the bus->devices list and confuse the
0074      * iterator.  Therefore, iterate in reverse so we remove the VFs
0075      * first, then the PF.
0076      */
0077     if (bus) {
0078         list_for_each_entry_safe_reverse(child, tmp,
0079                          &bus->devices, bus_list)
0080             pci_stop_bus_device(child);
0081     }
0082 
0083     pci_stop_dev(dev);
0084 }
0085 
0086 static void pci_remove_bus_device(struct pci_dev *dev)
0087 {
0088     struct pci_bus *bus = dev->subordinate;
0089     struct pci_dev *child, *tmp;
0090 
0091     if (bus) {
0092         list_for_each_entry_safe(child, tmp,
0093                      &bus->devices, bus_list)
0094             pci_remove_bus_device(child);
0095 
0096         pci_remove_bus(bus);
0097         dev->subordinate = NULL;
0098     }
0099 
0100     pci_destroy_dev(dev);
0101 }
0102 
0103 /**
0104  * pci_stop_and_remove_bus_device - remove a PCI device and any children
0105  * @dev: the device to remove
0106  *
0107  * Remove a PCI device from the device lists, informing the drivers
0108  * that the device has been removed.  We also remove any subordinate
0109  * buses and children in a depth-first manner.
0110  *
0111  * For each device we remove, delete the device structure from the
0112  * device lists, remove the /proc entry, and notify userspace
0113  * (/sbin/hotplug).
0114  */
0115 void pci_stop_and_remove_bus_device(struct pci_dev *dev)
0116 {
0117     pci_stop_bus_device(dev);
0118     pci_remove_bus_device(dev);
0119 }
0120 EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
0121 
0122 void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev)
0123 {
0124     pci_lock_rescan_remove();
0125     pci_stop_and_remove_bus_device(dev);
0126     pci_unlock_rescan_remove();
0127 }
0128 EXPORT_SYMBOL_GPL(pci_stop_and_remove_bus_device_locked);
0129 
0130 void pci_stop_root_bus(struct pci_bus *bus)
0131 {
0132     struct pci_dev *child, *tmp;
0133     struct pci_host_bridge *host_bridge;
0134 
0135     if (!pci_is_root_bus(bus))
0136         return;
0137 
0138     host_bridge = to_pci_host_bridge(bus->bridge);
0139     list_for_each_entry_safe_reverse(child, tmp,
0140                      &bus->devices, bus_list)
0141         pci_stop_bus_device(child);
0142 
0143     /* stop the host bridge */
0144     device_release_driver(&host_bridge->dev);
0145 }
0146 EXPORT_SYMBOL_GPL(pci_stop_root_bus);
0147 
0148 void pci_remove_root_bus(struct pci_bus *bus)
0149 {
0150     struct pci_dev *child, *tmp;
0151     struct pci_host_bridge *host_bridge;
0152 
0153     if (!pci_is_root_bus(bus))
0154         return;
0155 
0156     host_bridge = to_pci_host_bridge(bus->bridge);
0157     list_for_each_entry_safe(child, tmp,
0158                  &bus->devices, bus_list)
0159         pci_remove_bus_device(child);
0160     pci_remove_bus(bus);
0161     host_bridge->bus = NULL;
0162 
0163     /* remove the host bridge */
0164     device_del(&host_bridge->dev);
0165 }
0166 EXPORT_SYMBOL_GPL(pci_remove_root_bus);