Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0 2 : #include <linux/pci.h> 3 : #include <linux/module.h> 4 : #include "pci.h" 5 : 6 : static void pci_free_resources(struct pci_dev *dev) 7 : { 8 : struct resource *res; 9 : 10 0 : pci_dev_for_each_resource(dev, res) { 11 0 : if (res->parent) 12 0 : release_resource(res); 13 : } 14 : } 15 : 16 0 : static void pci_stop_dev(struct pci_dev *dev) 17 : { 18 0 : pci_pme_active(dev, false); 19 : 20 0 : if (pci_dev_is_added(dev)) { 21 : 22 0 : device_release_driver(&dev->dev); 23 0 : pci_proc_detach_device(dev); 24 0 : pci_remove_sysfs_dev_files(dev); 25 : 26 : pci_dev_assign_added(dev, false); 27 : } 28 0 : } 29 : 30 0 : static void pci_destroy_dev(struct pci_dev *dev) 31 : { 32 0 : if (!dev->dev.kobj.parent) 33 : return; 34 : 35 0 : device_del(&dev->dev); 36 : 37 0 : down_write(&pci_bus_sem); 38 0 : list_del(&dev->bus_list); 39 0 : up_write(&pci_bus_sem); 40 : 41 0 : pci_doe_destroy(dev); 42 0 : pcie_aspm_exit_link_state(dev); 43 0 : pci_bridge_d3_update(dev); 44 0 : pci_free_resources(dev); 45 0 : put_device(&dev->dev); 46 : } 47 : 48 0 : void pci_remove_bus(struct pci_bus *bus) 49 : { 50 0 : pci_proc_detach_bus(bus); 51 : 52 0 : down_write(&pci_bus_sem); 53 0 : list_del(&bus->node); 54 0 : pci_bus_release_busn_res(bus); 55 0 : up_write(&pci_bus_sem); 56 0 : pci_remove_legacy_files(bus); 57 : 58 0 : if (bus->ops->remove_bus) 59 0 : bus->ops->remove_bus(bus); 60 : 61 0 : pcibios_remove_bus(bus); 62 0 : device_unregister(&bus->dev); 63 0 : } 64 : EXPORT_SYMBOL(pci_remove_bus); 65 : 66 0 : static void pci_stop_bus_device(struct pci_dev *dev) 67 : { 68 0 : struct pci_bus *bus = dev->subordinate; 69 : struct pci_dev *child, *tmp; 70 : 71 : /* 72 : * Stopping an SR-IOV PF device removes all the associated VFs, 73 : * which will update the bus->devices list and confuse the 74 : * iterator. Therefore, iterate in reverse so we remove the VFs 75 : * first, then the PF. 76 : */ 77 0 : if (bus) { 78 0 : list_for_each_entry_safe_reverse(child, tmp, 79 : &bus->devices, bus_list) 80 0 : pci_stop_bus_device(child); 81 : } 82 : 83 0 : pci_stop_dev(dev); 84 0 : } 85 : 86 0 : static void pci_remove_bus_device(struct pci_dev *dev) 87 : { 88 0 : struct pci_bus *bus = dev->subordinate; 89 : struct pci_dev *child, *tmp; 90 : 91 0 : if (bus) { 92 0 : list_for_each_entry_safe(child, tmp, 93 : &bus->devices, bus_list) 94 0 : pci_remove_bus_device(child); 95 : 96 0 : pci_remove_bus(bus); 97 0 : dev->subordinate = NULL; 98 : } 99 : 100 0 : pci_destroy_dev(dev); 101 0 : } 102 : 103 : /** 104 : * pci_stop_and_remove_bus_device - remove a PCI device and any children 105 : * @dev: the device to remove 106 : * 107 : * Remove a PCI device from the device lists, informing the drivers 108 : * that the device has been removed. We also remove any subordinate 109 : * buses and children in a depth-first manner. 110 : * 111 : * For each device we remove, delete the device structure from the 112 : * device lists, remove the /proc entry, and notify userspace 113 : * (/sbin/hotplug). 114 : */ 115 0 : void pci_stop_and_remove_bus_device(struct pci_dev *dev) 116 : { 117 0 : pci_stop_bus_device(dev); 118 0 : pci_remove_bus_device(dev); 119 0 : } 120 : EXPORT_SYMBOL(pci_stop_and_remove_bus_device); 121 : 122 0 : void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev) 123 : { 124 0 : pci_lock_rescan_remove(); 125 0 : pci_stop_and_remove_bus_device(dev); 126 0 : pci_unlock_rescan_remove(); 127 0 : } 128 : EXPORT_SYMBOL_GPL(pci_stop_and_remove_bus_device_locked); 129 : 130 0 : void pci_stop_root_bus(struct pci_bus *bus) 131 : { 132 : struct pci_dev *child, *tmp; 133 : struct pci_host_bridge *host_bridge; 134 : 135 0 : if (!pci_is_root_bus(bus)) 136 : return; 137 : 138 0 : host_bridge = to_pci_host_bridge(bus->bridge); 139 0 : list_for_each_entry_safe_reverse(child, tmp, 140 : &bus->devices, bus_list) 141 0 : pci_stop_bus_device(child); 142 : 143 : /* stop the host bridge */ 144 0 : device_release_driver(&host_bridge->dev); 145 : } 146 : EXPORT_SYMBOL_GPL(pci_stop_root_bus); 147 : 148 0 : void pci_remove_root_bus(struct pci_bus *bus) 149 : { 150 : struct pci_dev *child, *tmp; 151 : struct pci_host_bridge *host_bridge; 152 : 153 0 : if (!pci_is_root_bus(bus)) 154 : return; 155 : 156 0 : host_bridge = to_pci_host_bridge(bus->bridge); 157 0 : list_for_each_entry_safe(child, tmp, 158 : &bus->devices, bus_list) 159 0 : pci_remove_bus_device(child); 160 : 161 : #ifdef CONFIG_PCI_DOMAINS_GENERIC 162 : /* Release domain_nr if it was dynamically allocated */ 163 : if (host_bridge->domain_nr == PCI_DOMAIN_NR_NOT_SET) 164 : pci_bus_release_domain_nr(bus, host_bridge->dev.parent); 165 : #endif 166 : 167 0 : pci_remove_bus(bus); 168 0 : host_bridge->bus = NULL; 169 : 170 : /* remove the host bridge */ 171 0 : device_del(&host_bridge->dev); 172 : } 173 : EXPORT_SYMBOL_GPL(pci_remove_root_bus);