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