Something went wrong. Try again.
(I'm so sorry!) Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188// SPDX-License-Identifier: GPL-2.0#include <linux/pci.h>#include <linux/module.h>#include <linux/of.h>#include <linux/of_platform.h>#include <linux/platform_device.h>
#include "pci.h"
static void pci_free_resources(struct pci_dev *dev){ struct resource *res;
pci_dev_for_each_resource(dev, res) { if (res->parent) release_resource(res); }}
static void pci_stop_dev(struct pci_dev *dev){ pci_pme_active(dev, false);
if (!pci_dev_test_and_clear_added(dev)) return;
device_release_driver(&dev->dev); pci_proc_detach_device(dev); of_pci_remove_node(dev);}
static void pci_destroy_dev(struct pci_dev *dev){ if (pci_dev_test_and_set_removed(dev)) return;
platform_pci_remove_wake(dev); pci_doe_sysfs_teardown(dev); pci_npem_remove(dev);
/* * While device is in D0 drop the device from TSM link operations * including unbind and disconnect (IDE + SPDM teardown). */ pci_tsm_destroy(dev);
device_del(&dev->dev);
down_write(&pci_bus_sem); list_del(&dev->bus_list); up_write(&pci_bus_sem);
pci_doe_destroy(dev); pci_ide_destroy(dev); pcie_aspm_exit_link_state(dev); pci_bridge_d3_update(dev); pci_free_resources(dev); put_device(&dev->dev);}
void pci_remove_bus(struct pci_bus *bus){ pci_proc_detach_bus(bus);
down_write(&pci_bus_sem); list_del(&bus->node); pci_bus_release_busn_res(bus); up_write(&pci_bus_sem); if (bus->ops->remove_bus) bus->ops->remove_bus(bus);
pcibios_remove_bus(bus); device_unregister(&bus->dev);}EXPORT_SYMBOL(pci_remove_bus);
static void pci_stop_bus_device(struct pci_dev *dev){ struct pci_bus *bus = dev->subordinate; struct pci_dev *child, *tmp;
/* * Stopping an SR-IOV PF device removes all the associated VFs, * which will update the bus->devices list and confuse the * iterator. Therefore, iterate in reverse so we remove the VFs * first, then the PF. */ if (bus) { list_for_each_entry_safe_reverse(child, tmp, &bus->devices, bus_list) pci_stop_bus_device(child); }
pci_stop_dev(dev);}
static void pci_remove_bus_device(struct pci_dev *dev){ struct pci_bus *bus = dev->subordinate; struct pci_dev *child, *tmp;
if (bus) { list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) pci_remove_bus_device(child);
pci_remove_bus(bus); dev->subordinate = NULL; }
pci_destroy_dev(dev);}
/** * pci_stop_and_remove_bus_device - remove a PCI device and any children * @dev: the device to remove * * Remove a PCI device from the device lists, informing the drivers * that the device has been removed. We also remove any subordinate * buses and children in a depth-first manner. * * For each device we remove, delete the device structure from the * device lists, remove the /proc entry, and notify userspace * (/sbin/hotplug). */void pci_stop_and_remove_bus_device(struct pci_dev *dev){ lockdep_assert_held(&pci_rescan_remove_lock); pci_stop_bus_device(dev); pci_remove_bus_device(dev);}EXPORT_SYMBOL(pci_stop_and_remove_bus_device);
void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev){ pci_lock_rescan_remove(); pci_stop_and_remove_bus_device(dev); pci_unlock_rescan_remove();}EXPORT_SYMBOL_GPL(pci_stop_and_remove_bus_device_locked);
void pci_stop_root_bus(struct pci_bus *bus){ struct pci_dev *child, *tmp; struct pci_host_bridge *host_bridge;
if (!pci_is_root_bus(bus)) return;
host_bridge = to_pci_host_bridge(bus->bridge); list_for_each_entry_safe_reverse(child, tmp, &bus->devices, bus_list) pci_stop_bus_device(child);
of_pci_remove_host_bridge_node(host_bridge);
/* stop the host bridge */ device_release_driver(&host_bridge->dev);}EXPORT_SYMBOL_GPL(pci_stop_root_bus);
void pci_remove_root_bus(struct pci_bus *bus){ struct pci_dev *child, *tmp; struct pci_host_bridge *host_bridge;
if (!pci_is_root_bus(bus)) return;
host_bridge = to_pci_host_bridge(bus->bridge); list_for_each_entry_safe(child, tmp, &bus->devices, bus_list) pci_remove_bus_device(child);
#ifdef CONFIG_PCI_DOMAINS_GENERIC /* Release domain_nr if it was dynamically allocated */ if (host_bridge->domain_nr == PCI_DOMAIN_NR_NOT_SET) pci_bus_release_domain_nr(host_bridge->dev.parent, bus->domain_nr);#endif
pci_remove_bus(bus); host_bridge->bus = NULL;
/* remove the host bridge */ device_del(&host_bridge->dev);}EXPORT_SYMBOL_GPL(pci_remove_root_bus);