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