root/drivers/pci/remove.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pci_free_resources
  2. pci_stop_dev
  3. pci_destroy_dev
  4. pci_remove_bus
  5. pci_stop_bus_device
  6. pci_remove_bus_device
  7. pci_stop_and_remove_bus_device
  8. pci_stop_and_remove_bus_device_locked
  9. pci_stop_root_bus
  10. pci_remove_root_bus

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <linux/pci.h>
   3 #include <linux/module.h>
   4 #include "pci.h"
   5 
   6 static void pci_free_resources(struct pci_dev *dev)
   7 {
   8         int i;
   9 
  10         for (i = 0; i < PCI_NUM_RESOURCES; i++) {
  11                 struct resource *res = dev->resource + i;
  12                 if (res->parent)
  13                         release_resource(res);
  14         }
  15 }
  16 
  17 static void pci_stop_dev(struct pci_dev *dev)
  18 {
  19         pci_pme_active(dev, false);
  20 
  21         if (pci_dev_is_added(dev)) {
  22                 device_release_driver(&dev->dev);
  23                 pci_proc_detach_device(dev);
  24                 pci_remove_sysfs_dev_files(dev);
  25 
  26                 pci_dev_assign_added(dev, false);
  27         }
  28 }
  29 
  30 static void pci_destroy_dev(struct pci_dev *dev)
  31 {
  32         if (!dev->dev.kobj.parent)
  33                 return;
  34 
  35         device_del(&dev->dev);
  36 
  37         down_write(&pci_bus_sem);
  38         list_del(&dev->bus_list);
  39         up_write(&pci_bus_sem);
  40 
  41         pcie_aspm_exit_link_state(dev);
  42         pci_bridge_d3_update(dev);
  43         pci_free_resources(dev);
  44         put_device(&dev->dev);
  45 }
  46 
  47 void pci_remove_bus(struct pci_bus *bus)
  48 {
  49         pci_proc_detach_bus(bus);
  50 
  51         down_write(&pci_bus_sem);
  52         list_del(&bus->node);
  53         pci_bus_release_busn_res(bus);
  54         up_write(&pci_bus_sem);
  55         pci_remove_legacy_files(bus);
  56 
  57         if (bus->ops->remove_bus)
  58                 bus->ops->remove_bus(bus);
  59 
  60         pcibios_remove_bus(bus);
  61         device_unregister(&bus->dev);
  62 }
  63 EXPORT_SYMBOL(pci_remove_bus);
  64 
  65 static void pci_stop_bus_device(struct pci_dev *dev)
  66 {
  67         struct pci_bus *bus = dev->subordinate;
  68         struct pci_dev *child, *tmp;
  69 
  70         /*
  71          * Stopping an SR-IOV PF device removes all the associated VFs,
  72          * which will update the bus->devices list and confuse the
  73          * iterator.  Therefore, iterate in reverse so we remove the VFs
  74          * first, then the PF.
  75          */
  76         if (bus) {
  77                 list_for_each_entry_safe_reverse(child, tmp,
  78                                                  &bus->devices, bus_list)
  79                         pci_stop_bus_device(child);
  80         }
  81 
  82         pci_stop_dev(dev);
  83 }
  84 
  85 static void pci_remove_bus_device(struct pci_dev *dev)
  86 {
  87         struct pci_bus *bus = dev->subordinate;
  88         struct pci_dev *child, *tmp;
  89 
  90         if (bus) {
  91                 list_for_each_entry_safe(child, tmp,
  92                                          &bus->devices, bus_list)
  93                         pci_remove_bus_device(child);
  94 
  95                 pci_remove_bus(bus);
  96                 dev->subordinate = NULL;
  97         }
  98 
  99         pci_destroy_dev(dev);
 100 }
 101 
 102 /**
 103  * pci_stop_and_remove_bus_device - remove a PCI device and any children
 104  * @dev: the device to remove
 105  *
 106  * Remove a PCI device from the device lists, informing the drivers
 107  * that the device has been removed.  We also remove any subordinate
 108  * buses and children in a depth-first manner.
 109  *
 110  * For each device we remove, delete the device structure from the
 111  * device lists, remove the /proc entry, and notify userspace
 112  * (/sbin/hotplug).
 113  */
 114 void pci_stop_and_remove_bus_device(struct pci_dev *dev)
 115 {
 116         pci_stop_bus_device(dev);
 117         pci_remove_bus_device(dev);
 118 }
 119 EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
 120 
 121 void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev)
 122 {
 123         pci_lock_rescan_remove();
 124         pci_stop_and_remove_bus_device(dev);
 125         pci_unlock_rescan_remove();
 126 }
 127 EXPORT_SYMBOL_GPL(pci_stop_and_remove_bus_device_locked);
 128 
 129 void pci_stop_root_bus(struct pci_bus *bus)
 130 {
 131         struct pci_dev *child, *tmp;
 132         struct pci_host_bridge *host_bridge;
 133 
 134         if (!pci_is_root_bus(bus))
 135                 return;
 136 
 137         host_bridge = to_pci_host_bridge(bus->bridge);
 138         list_for_each_entry_safe_reverse(child, tmp,
 139                                          &bus->devices, bus_list)
 140                 pci_stop_bus_device(child);
 141 
 142         /* stop the host bridge */
 143         device_release_driver(&host_bridge->dev);
 144 }
 145 EXPORT_SYMBOL_GPL(pci_stop_root_bus);
 146 
 147 void pci_remove_root_bus(struct pci_bus *bus)
 148 {
 149         struct pci_dev *child, *tmp;
 150         struct pci_host_bridge *host_bridge;
 151 
 152         if (!pci_is_root_bus(bus))
 153                 return;
 154 
 155         host_bridge = to_pci_host_bridge(bus->bridge);
 156         list_for_each_entry_safe(child, tmp,
 157                                  &bus->devices, bus_list)
 158                 pci_remove_bus_device(child);
 159         pci_remove_bus(bus);
 160         host_bridge->bus = NULL;
 161 
 162         /* remove the host bridge */
 163         device_unregister(&host_bridge->dev);
 164 }
 165 EXPORT_SYMBOL_GPL(pci_remove_root_bus);

/* [<][>][^][v][top][bottom][index][help] */