LCOV - code coverage report
Current view: top level - drivers/pci - remove.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 74 0.0 %
Date: 2023-04-06 08:38:28 Functions: 0 10 0.0 %

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

Generated by: LCOV version 1.14