summaryrefslogtreecommitdiff
path: root/drivers/pci/remove.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/remove.c')
-rw-r--r--drivers/pci/remove.c94
1 files changed, 77 insertions, 17 deletions
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 8fc54b7327bc..417a9ea59117 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -1,43 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0
#include <linux/pci.h>
#include <linux/module.h>
-#include <linux/pci-aspm.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+
#include "pci.h"
static void pci_free_resources(struct pci_dev *dev)
{
- int i;
-
- msi_remove_pci_irq_vectors(dev);
+ struct resource *res;
- pci_cleanup_rom(dev);
- for (i = 0; i < PCI_NUM_RESOURCES; i++) {
- struct resource *res = dev->resource + i;
+ pci_dev_for_each_resource(dev, res) {
if (res->parent)
release_resource(res);
}
}
+static void pci_pwrctrl_unregister(struct device *dev)
+{
+ struct device_node *np;
+ struct platform_device *pdev;
+
+ np = dev_of_node(dev);
+ if (!np)
+ return;
+
+ pdev = of_find_device_by_node(np);
+ if (!pdev)
+ return;
+
+ of_device_unregister(pdev);
+ put_device(&pdev->dev);
+
+ of_node_clear_flag(np, OF_POPULATED);
+}
+
static void pci_stop_dev(struct pci_dev *dev)
{
pci_pme_active(dev, false);
- if (dev->is_added) {
- pci_proc_detach_device(dev);
- pci_remove_sysfs_dev_files(dev);
- device_del(&dev->dev);
- dev->is_added = 0;
- }
+ if (!pci_dev_test_and_clear_added(dev))
+ return;
- if (dev->bus->self)
- pcie_aspm_exit_link_state(dev);
+ device_release_driver(&dev->dev);
+ pci_proc_detach_device(dev);
+ pci_remove_sysfs_dev_files(dev);
+ of_pci_remove_node(dev);
}
static void pci_destroy_dev(struct pci_dev *dev)
{
+ if (pci_dev_test_and_set_removed(dev))
+ return;
+
+ pci_doe_sysfs_teardown(dev);
+ pci_npem_remove(dev);
+
+ /*
+ * While device is in D0 drop the device from TSM link operations
+ * including unbind and disconnect (IDE + SPDM teardown).
+ */
+ pci_tsm_destroy(dev);
+
+ device_del(&dev->dev);
+
down_write(&pci_bus_sem);
list_del(&dev->bus_list);
up_write(&pci_bus_sem);
+ pci_doe_destroy(dev);
+ pci_ide_destroy(dev);
+ pcie_aspm_exit_link_state(dev);
+ pci_bridge_d3_update(dev);
+ pci_pwrctrl_unregister(&dev->dev);
pci_free_resources(dev);
put_device(&dev->dev);
}
@@ -51,6 +87,10 @@ void pci_remove_bus(struct pci_bus *bus)
pci_bus_release_busn_res(bus);
up_write(&pci_bus_sem);
pci_remove_legacy_files(bus);
+
+ if (bus->ops->remove_bus)
+ bus->ops->remove_bus(bus);
+
pcibios_remove_bus(bus);
device_unregister(&bus->dev);
}
@@ -107,11 +147,20 @@ static void pci_remove_bus_device(struct pci_dev *dev)
*/
void pci_stop_and_remove_bus_device(struct pci_dev *dev)
{
+ lockdep_assert_held(&pci_rescan_remove_lock);
pci_stop_bus_device(dev);
pci_remove_bus_device(dev);
}
EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
+void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev)
+{
+ pci_lock_rescan_remove();
+ pci_stop_and_remove_bus_device(dev);
+ pci_unlock_rescan_remove();
+}
+EXPORT_SYMBOL_GPL(pci_stop_and_remove_bus_device_locked);
+
void pci_stop_root_bus(struct pci_bus *bus)
{
struct pci_dev *child, *tmp;
@@ -125,9 +174,12 @@ void pci_stop_root_bus(struct pci_bus *bus)
&bus->devices, bus_list)
pci_stop_bus_device(child);
+ of_pci_remove_host_bridge_node(host_bridge);
+
/* stop the host bridge */
- device_del(&host_bridge->dev);
+ device_release_driver(&host_bridge->dev);
}
+EXPORT_SYMBOL_GPL(pci_stop_root_bus);
void pci_remove_root_bus(struct pci_bus *bus)
{
@@ -141,9 +193,17 @@ void pci_remove_root_bus(struct pci_bus *bus)
list_for_each_entry_safe(child, tmp,
&bus->devices, bus_list)
pci_remove_bus_device(child);
+
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
+ /* Release domain_nr if it was dynamically allocated */
+ if (host_bridge->domain_nr == PCI_DOMAIN_NR_NOT_SET)
+ pci_bus_release_domain_nr(host_bridge->dev.parent, bus->domain_nr);
+#endif
+
pci_remove_bus(bus);
host_bridge->bus = NULL;
/* remove the host bridge */
- put_device(&host_bridge->dev);
+ device_del(&host_bridge->dev);
}
+EXPORT_SYMBOL_GPL(pci_remove_root_bus);