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