at v3.9-rc2 151 lines 3.3 kB view raw
1#include <linux/pci.h> 2#include <linux/module.h> 3#include <linux/pci-aspm.h> 4#include "pci.h" 5 6static 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 20static 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_del(&dev->dev); 28 dev->is_added = 0; 29 } 30 31 if (dev->bus->self) 32 pcie_aspm_exit_link_state(dev); 33} 34 35static void pci_destroy_dev(struct pci_dev *dev) 36{ 37 down_write(&pci_bus_sem); 38 list_del(&dev->bus_list); 39 up_write(&pci_bus_sem); 40 41 pci_free_resources(dev); 42 put_device(&dev->dev); 43} 44 45void pci_remove_bus(struct pci_bus *bus) 46{ 47 pci_proc_detach_bus(bus); 48 49 down_write(&pci_bus_sem); 50 list_del(&bus->node); 51 pci_bus_release_busn_res(bus); 52 up_write(&pci_bus_sem); 53 if (!bus->is_added) 54 return; 55 56 pci_remove_legacy_files(bus); 57 device_unregister(&bus->dev); 58} 59EXPORT_SYMBOL(pci_remove_bus); 60 61static 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 81static 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 */ 110void pci_stop_and_remove_bus_device(struct pci_dev *dev) 111{ 112 pci_stop_bus_device(dev); 113 pci_remove_bus_device(dev); 114} 115EXPORT_SYMBOL(pci_stop_and_remove_bus_device); 116 117void 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 134void 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}