remove.c 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. #include <linux/pci.h>
  2. #include <linux/module.h>
  3. #include <linux/pci-aspm.h>
  4. #include "pci.h"
  5. static void pci_free_resources(struct pci_dev *dev)
  6. {
  7. int i;
  8. msi_remove_pci_irq_vectors(dev);
  9. pci_cleanup_rom(dev);
  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. static void pci_stop_dev(struct pci_dev *dev)
  17. {
  18. if (dev->is_added) {
  19. pci_proc_detach_device(dev);
  20. pci_remove_sysfs_dev_files(dev);
  21. device_unregister(&dev->dev);
  22. dev->is_added = 0;
  23. }
  24. if (dev->bus->self)
  25. pcie_aspm_exit_link_state(dev);
  26. }
  27. static void pci_destroy_dev(struct pci_dev *dev)
  28. {
  29. down_write(&pci_bus_sem);
  30. list_del(&dev->bus_list);
  31. up_write(&pci_bus_sem);
  32. pci_free_resources(dev);
  33. pci_dev_put(dev);
  34. }
  35. void pci_remove_bus(struct pci_bus *bus)
  36. {
  37. pci_proc_detach_bus(bus);
  38. down_write(&pci_bus_sem);
  39. list_del(&bus->node);
  40. pci_bus_release_busn_res(bus);
  41. up_write(&pci_bus_sem);
  42. if (!bus->is_added)
  43. return;
  44. pci_remove_legacy_files(bus);
  45. device_unregister(&bus->dev);
  46. }
  47. EXPORT_SYMBOL(pci_remove_bus);
  48. /**
  49. * pci_stop_and_remove_bus_device - remove a PCI device and any children
  50. * @dev: the device to remove
  51. *
  52. * Remove a PCI device from the device lists, informing the drivers
  53. * that the device has been removed. We also remove any subordinate
  54. * buses and children in a depth-first manner.
  55. *
  56. * For each device we remove, delete the device structure from the
  57. * device lists, remove the /proc entry, and notify userspace
  58. * (/sbin/hotplug).
  59. */
  60. void pci_stop_and_remove_bus_device(struct pci_dev *dev)
  61. {
  62. struct pci_bus *bus = dev->subordinate;
  63. struct pci_dev *child, *tmp;
  64. /*
  65. * Removing an SR-IOV PF device removes all the associated VFs,
  66. * which will update the bus->devices list and confuse the
  67. * iterator. Therefore, iterate in reverse so we remove the VFs
  68. * first, then the PF.
  69. */
  70. if (bus) {
  71. list_for_each_entry_safe_reverse(child, tmp,
  72. &bus->devices, bus_list)
  73. pci_stop_and_remove_bus_device(child);
  74. pci_remove_bus(bus);
  75. dev->subordinate = NULL;
  76. }
  77. pci_stop_dev(dev);
  78. pci_destroy_dev(dev);
  79. }
  80. EXPORT_SYMBOL(pci_stop_and_remove_bus_device);