1 #include <linux/pci.h> 2 #include <linux/module.h> 3 #include <linux/pci-aspm.h> 4 #include "pci.h" 5 6 static void pci_free_resources(struct pci_dev *dev) 7 { 8 int i; 9 10 msi_remove_pci_irq_vectors(dev); 11 12 pci_cleanup_rom(dev); 13 for (i = 0; i < PCI_NUM_RESOURCES; i++) { 14 struct resource *res = dev->resource + i; 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 (dev->is_added) { 25 pci_proc_detach_device(dev); 26 pci_remove_sysfs_dev_files(dev); 27 device_release_driver(&dev->dev); 28 dev->is_added = 0; 29 } 30 31 if (dev->bus->self) 32 pcie_aspm_exit_link_state(dev); 33 } 34 35 static void pci_destroy_dev(struct pci_dev *dev) 36 { 37 device_del(&dev->dev); 38 39 down_write(&pci_bus_sem); 40 list_del(&dev->bus_list); 41 up_write(&pci_bus_sem); 42 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 pcibios_remove_bus(bus); 57 device_unregister(&bus->dev); 58 } 59 EXPORT_SYMBOL(pci_remove_bus); 60 61 static void pci_stop_bus_device(struct pci_dev *dev) 62 { 63 struct pci_bus *bus = dev->subordinate; 64 struct pci_dev *child, *tmp; 65 66 /* 67 * Stopping an SR-IOV PF device removes all the associated VFs, 68 * which will update the bus->devices list and confuse the 69 * iterator. Therefore, iterate in reverse so we remove the VFs 70 * first, then the PF. 71 */ 72 if (bus) { 73 list_for_each_entry_safe_reverse(child, tmp, 74 &bus->devices, bus_list) 75 pci_stop_bus_device(child); 76 } 77 78 pci_stop_dev(dev); 79 } 80 81 static void pci_remove_bus_device(struct pci_dev *dev) 82 { 83 struct pci_bus *bus = dev->subordinate; 84 struct pci_dev *child, *tmp; 85 86 if (bus) { 87 list_for_each_entry_safe(child, tmp, 88 &bus->devices, bus_list) 89 pci_remove_bus_device(child); 90 91 pci_remove_bus(bus); 92 dev->subordinate = NULL; 93 } 94 95 pci_destroy_dev(dev); 96 } 97 98 /** 99 * pci_stop_and_remove_bus_device - remove a PCI device and any children 100 * @dev: the device to remove 101 * 102 * Remove a PCI device from the device lists, informing the drivers 103 * that the device has been removed. We also remove any subordinate 104 * buses and children in a depth-first manner. 105 * 106 * For each device we remove, delete the device structure from the 107 * device lists, remove the /proc entry, and notify userspace 108 * (/sbin/hotplug). 109 */ 110 void pci_stop_and_remove_bus_device(struct pci_dev *dev) 111 { 112 pci_stop_bus_device(dev); 113 pci_remove_bus_device(dev); 114 } 115 EXPORT_SYMBOL(pci_stop_and_remove_bus_device); 116 117 void pci_stop_root_bus(struct pci_bus *bus) 118 { 119 struct pci_dev *child, *tmp; 120 struct pci_host_bridge *host_bridge; 121 122 if (!pci_is_root_bus(bus)) 123 return; 124 125 host_bridge = to_pci_host_bridge(bus->bridge); 126 list_for_each_entry_safe_reverse(child, tmp, 127 &bus->devices, bus_list) 128 pci_stop_bus_device(child); 129 130 /* stop the host bridge */ 131 device_del(&host_bridge->dev); 132 } 133 134 void pci_remove_root_bus(struct pci_bus *bus) 135 { 136 struct pci_dev *child, *tmp; 137 struct pci_host_bridge *host_bridge; 138 139 if (!pci_is_root_bus(bus)) 140 return; 141 142 host_bridge = to_pci_host_bridge(bus->bridge); 143 list_for_each_entry_safe(child, tmp, 144 &bus->devices, bus_list) 145 pci_remove_bus_device(child); 146 pci_remove_bus(bus); 147 host_bridge->bus = NULL; 148 149 /* remove the host bridge */ 150 put_device(&host_bridge->dev); 151 } 152