cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

remove.c (3765B)


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