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