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 device_del(&dev->dev); 61 62 down_write(&pci_bus_sem); 63 list_del(&dev->bus_list); 64 up_write(&pci_bus_sem); 65 66 pci_doe_destroy(dev); 67 pcie_aspm_exit_link_state(dev); 68 pci_bridge_d3_update(dev); 69 pci_pwrctrl_unregister(&dev->dev); 70 pci_free_resources(dev); 71 put_device(&dev->dev); 72 } 73 74 void pci_remove_bus(struct pci_bus *bus) 75 { 76 pci_proc_detach_bus(bus); 77 78 down_write(&pci_bus_sem); 79 list_del(&bus->node); 80 pci_bus_release_busn_res(bus); 81 up_write(&pci_bus_sem); 82 pci_remove_legacy_files(bus); 83 84 if (bus->ops->remove_bus) 85 bus->ops->remove_bus(bus); 86 87 pcibios_remove_bus(bus); 88 device_unregister(&bus->dev); 89 } 90 EXPORT_SYMBOL(pci_remove_bus); 91 92 static void pci_stop_bus_device(struct pci_dev *dev) 93 { 94 struct pci_bus *bus = dev->subordinate; 95 struct pci_dev *child, *tmp; 96 97 /* 98 * Stopping an SR-IOV PF device removes all the associated VFs, 99 * which will update the bus->devices list and confuse the 100 * iterator. Therefore, iterate in reverse so we remove the VFs 101 * first, then the PF. 102 */ 103 if (bus) { 104 list_for_each_entry_safe_reverse(child, tmp, 105 &bus->devices, bus_list) 106 pci_stop_bus_device(child); 107 } 108 109 pci_stop_dev(dev); 110 } 111 112 static void pci_remove_bus_device(struct pci_dev *dev) 113 { 114 struct pci_bus *bus = dev->subordinate; 115 struct pci_dev *child, *tmp; 116 117 if (bus) { 118 list_for_each_entry_safe(child, tmp, 119 &bus->devices, bus_list) 120 pci_remove_bus_device(child); 121 122 pci_remove_bus(bus); 123 dev->subordinate = NULL; 124 } 125 126 pci_destroy_dev(dev); 127 } 128 129 /** 130 * pci_stop_and_remove_bus_device - remove a PCI device and any children 131 * @dev: the device to remove 132 * 133 * Remove a PCI device from the device lists, informing the drivers 134 * that the device has been removed. We also remove any subordinate 135 * buses and children in a depth-first manner. 136 * 137 * For each device we remove, delete the device structure from the 138 * device lists, remove the /proc entry, and notify userspace 139 * (/sbin/hotplug). 140 */ 141 void pci_stop_and_remove_bus_device(struct pci_dev *dev) 142 { 143 lockdep_assert_held(&pci_rescan_remove_lock); 144 pci_stop_bus_device(dev); 145 pci_remove_bus_device(dev); 146 } 147 EXPORT_SYMBOL(pci_stop_and_remove_bus_device); 148 149 void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev) 150 { 151 pci_lock_rescan_remove(); 152 pci_stop_and_remove_bus_device(dev); 153 pci_unlock_rescan_remove(); 154 } 155 EXPORT_SYMBOL_GPL(pci_stop_and_remove_bus_device_locked); 156 157 void pci_stop_root_bus(struct pci_bus *bus) 158 { 159 struct pci_dev *child, *tmp; 160 struct pci_host_bridge *host_bridge; 161 162 if (!pci_is_root_bus(bus)) 163 return; 164 165 host_bridge = to_pci_host_bridge(bus->bridge); 166 list_for_each_entry_safe_reverse(child, tmp, 167 &bus->devices, bus_list) 168 pci_stop_bus_device(child); 169 170 of_pci_remove_host_bridge_node(host_bridge); 171 172 /* stop the host bridge */ 173 device_release_driver(&host_bridge->dev); 174 } 175 EXPORT_SYMBOL_GPL(pci_stop_root_bus); 176 177 void pci_remove_root_bus(struct pci_bus *bus) 178 { 179 struct pci_dev *child, *tmp; 180 struct pci_host_bridge *host_bridge; 181 182 if (!pci_is_root_bus(bus)) 183 return; 184 185 host_bridge = to_pci_host_bridge(bus->bridge); 186 list_for_each_entry_safe(child, tmp, 187 &bus->devices, bus_list) 188 pci_remove_bus_device(child); 189 190 #ifdef CONFIG_PCI_DOMAINS_GENERIC 191 /* Release domain_nr if it was dynamically allocated */ 192 if (host_bridge->domain_nr == PCI_DOMAIN_NR_NOT_SET) 193 pci_bus_release_domain_nr(host_bridge->dev.parent, bus->domain_nr); 194 #endif 195 196 pci_remove_bus(bus); 197 host_bridge->bus = NULL; 198 199 /* remove the host bridge */ 200 device_del(&host_bridge->dev); 201 } 202 EXPORT_SYMBOL_GPL(pci_remove_root_bus); 203