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