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