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