root/arch/powerpc/kernel/pci-hotplug.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. find_bus_among_children
  2. pci_find_bus_by_node
  3. pcibios_release_device
  4. pci_hp_remove_devices
  5. pci_hp_add_devices

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Derived from "arch/powerpc/platforms/pseries/pci_dlpar.c"
   4  *
   5  * Copyright (C) 2003 Linda Xie <lxie@us.ibm.com>
   6  * Copyright (C) 2005 International Business Machines
   7  *
   8  * Updates, 2005, John Rose <johnrose@austin.ibm.com>
   9  * Updates, 2005, Linas Vepstas <linas@austin.ibm.com>
  10  * Updates, 2013, Gavin Shan <shangw@linux.vnet.ibm.com>
  11  */
  12 
  13 #include <linux/pci.h>
  14 #include <linux/export.h>
  15 #include <asm/pci-bridge.h>
  16 #include <asm/ppc-pci.h>
  17 #include <asm/firmware.h>
  18 #include <asm/eeh.h>
  19 
  20 static struct pci_bus *find_bus_among_children(struct pci_bus *bus,
  21                                                struct device_node *dn)
  22 {
  23         struct pci_bus *child = NULL;
  24         struct pci_bus *tmp;
  25 
  26         if (pci_bus_to_OF_node(bus) == dn)
  27                 return bus;
  28 
  29         list_for_each_entry(tmp, &bus->children, node) {
  30                 child = find_bus_among_children(tmp, dn);
  31                 if (child)
  32                         break;
  33         }
  34 
  35         return child;
  36 }
  37 
  38 struct pci_bus *pci_find_bus_by_node(struct device_node *dn)
  39 {
  40         struct pci_dn *pdn = PCI_DN(dn);
  41 
  42         if (!pdn  || !pdn->phb || !pdn->phb->bus)
  43                 return NULL;
  44 
  45         return find_bus_among_children(pdn->phb->bus, dn);
  46 }
  47 EXPORT_SYMBOL_GPL(pci_find_bus_by_node);
  48 
  49 /**
  50  * pcibios_release_device - release PCI device
  51  * @dev: PCI device
  52  *
  53  * The function is called before releasing the indicated PCI device.
  54  */
  55 void pcibios_release_device(struct pci_dev *dev)
  56 {
  57         struct pci_controller *phb = pci_bus_to_host(dev->bus);
  58         struct pci_dn *pdn = pci_get_pdn(dev);
  59 
  60         eeh_remove_device(dev);
  61 
  62         if (phb->controller_ops.release_device)
  63                 phb->controller_ops.release_device(dev);
  64 
  65         /* free()ing the pci_dn has been deferred to us, do it now */
  66         if (pdn && (pdn->flags & PCI_DN_FLAG_DEAD)) {
  67                 pci_dbg(dev, "freeing dead pdn\n");
  68                 kfree(pdn);
  69         }
  70 }
  71 
  72 /**
  73  * pci_hp_remove_devices - remove all devices under this bus
  74  * @bus: the indicated PCI bus
  75  *
  76  * Remove all of the PCI devices under this bus both from the
  77  * linux pci device tree, and from the powerpc EEH address cache.
  78  */
  79 void pci_hp_remove_devices(struct pci_bus *bus)
  80 {
  81         struct pci_dev *dev, *tmp;
  82         struct pci_bus *child_bus;
  83 
  84         /* First go down child busses */
  85         list_for_each_entry(child_bus, &bus->children, node)
  86                 pci_hp_remove_devices(child_bus);
  87 
  88         pr_debug("PCI: Removing devices on bus %04x:%02x\n",
  89                  pci_domain_nr(bus),  bus->number);
  90         list_for_each_entry_safe_reverse(dev, tmp, &bus->devices, bus_list) {
  91                 pr_debug("   Removing %s...\n", pci_name(dev));
  92                 pci_stop_and_remove_bus_device(dev);
  93         }
  94 }
  95 EXPORT_SYMBOL_GPL(pci_hp_remove_devices);
  96 
  97 /**
  98  * pci_hp_add_devices - adds new pci devices to bus
  99  * @bus: the indicated PCI bus
 100  *
 101  * This routine will find and fixup new pci devices under
 102  * the indicated bus. This routine presumes that there
 103  * might already be some devices under this bridge, so
 104  * it carefully tries to add only new devices.  (And that
 105  * is how this routine differs from other, similar pcibios
 106  * routines.)
 107  */
 108 void pci_hp_add_devices(struct pci_bus *bus)
 109 {
 110         int slotno, mode, max;
 111         struct pci_dev *dev;
 112         struct pci_controller *phb;
 113         struct device_node *dn = pci_bus_to_OF_node(bus);
 114 
 115         eeh_add_device_tree_early(PCI_DN(dn));
 116 
 117         phb = pci_bus_to_host(bus);
 118 
 119         mode = PCI_PROBE_NORMAL;
 120         if (phb->controller_ops.probe_mode)
 121                 mode = phb->controller_ops.probe_mode(bus);
 122 
 123         if (mode == PCI_PROBE_DEVTREE) {
 124                 /* use ofdt-based probe */
 125                 of_rescan_bus(dn, bus);
 126         } else if (mode == PCI_PROBE_NORMAL &&
 127                    dn->child && PCI_DN(dn->child)) {
 128                 /*
 129                  * Use legacy probe. In the partial hotplug case, we
 130                  * probably have grandchildren devices unplugged. So
 131                  * we don't check the return value from pci_scan_slot() in
 132                  * order for fully rescan all the way down to pick them up.
 133                  * They can have been removed during partial hotplug.
 134                  */
 135                 slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
 136                 pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
 137                 pcibios_setup_bus_devices(bus);
 138                 max = bus->busn_res.start;
 139                 /*
 140                  * Scan bridges that are already configured. We don't touch
 141                  * them unless they are misconfigured (which will be done in
 142                  * the second scan below).
 143                  */
 144                 for_each_pci_bridge(dev, bus)
 145                         max = pci_scan_bridge(bus, dev, max, 0);
 146 
 147                 /* Scan bridges that need to be reconfigured */
 148                 for_each_pci_bridge(dev, bus)
 149                         max = pci_scan_bridge(bus, dev, max, 1);
 150         }
 151         pcibios_finish_adding_to_bus(bus);
 152 }
 153 EXPORT_SYMBOL_GPL(pci_hp_add_devices);

/* [<][>][^][v][top][bottom][index][help] */