~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/kernel/pci-hotplug.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 <linux/of.h>
 16 #include <asm/pci-bridge.h>
 17 #include <asm/ppc-pci.h>
 18 #include <asm/firmware.h>
 19 #include <asm/eeh.h>
 20 
 21 static struct pci_bus *find_bus_among_children(struct pci_bus *bus,
 22                                                struct device_node *dn)
 23 {
 24         struct pci_bus *child = NULL;
 25         struct pci_bus *tmp;
 26 
 27         if (pci_bus_to_OF_node(bus) == dn)
 28                 return bus;
 29 
 30         list_for_each_entry(tmp, &bus->children, node) {
 31                 child = find_bus_among_children(tmp, dn);
 32                 if (child)
 33                         break;
 34         }
 35 
 36         return child;
 37 }
 38 
 39 struct pci_bus *pci_find_bus_by_node(struct device_node *dn)
 40 {
 41         struct pci_dn *pdn = PCI_DN(dn);
 42 
 43         if (!pdn  || !pdn->phb || !pdn->phb->bus)
 44                 return NULL;
 45 
 46         return find_bus_among_children(pdn->phb->bus, dn);
 47 }
 48 EXPORT_SYMBOL_GPL(pci_find_bus_by_node);
 49 
 50 /**
 51  * pcibios_release_device - release PCI device
 52  * @dev: PCI device
 53  *
 54  * The function is called before releasing the indicated PCI device.
 55  */
 56 void pcibios_release_device(struct pci_dev *dev)
 57 {
 58         struct pci_controller *phb = pci_bus_to_host(dev->bus);
 59         struct pci_dn *pdn = pci_get_pdn(dev);
 60 
 61         if (phb->controller_ops.release_device)
 62                 phb->controller_ops.release_device(dev);
 63 
 64         /* free()ing the pci_dn has been deferred to us, do it now */
 65         if (pdn && (pdn->flags & PCI_DN_FLAG_DEAD)) {
 66                 pci_dbg(dev, "freeing dead pdn\n");
 67                 kfree(pdn);
 68         }
 69 }
 70 
 71 /**
 72  * pci_hp_remove_devices - remove all devices under this bus
 73  * @bus: the indicated PCI bus
 74  *
 75  * Remove all of the PCI devices under this bus both from the
 76  * linux pci device tree, and from the powerpc EEH address cache.
 77  */
 78 void pci_hp_remove_devices(struct pci_bus *bus)
 79 {
 80         struct pci_dev *dev, *tmp;
 81         struct pci_bus *child_bus;
 82 
 83         /* First go down child busses */
 84         list_for_each_entry(child_bus, &bus->children, node)
 85                 pci_hp_remove_devices(child_bus);
 86 
 87         pr_debug("PCI: Removing devices on bus %04x:%02x\n",
 88                  pci_domain_nr(bus),  bus->number);
 89         list_for_each_entry_safe_reverse(dev, tmp, &bus->devices, bus_list) {
 90                 pr_debug("   Removing %s...\n", pci_name(dev));
 91                 pci_stop_and_remove_bus_device(dev);
 92         }
 93 }
 94 EXPORT_SYMBOL_GPL(pci_hp_remove_devices);
 95 
 96 static void traverse_siblings_and_scan_slot(struct device_node *start, struct pci_bus *bus)
 97 {
 98         struct device_node *dn;
 99         int slotno;
100 
101         u32 class = 0;
102 
103         if (!of_property_read_u32(start->child, "class-code", &class)) {
104                 /* Call of pci_scan_slot for non-bridge/EP case */
105                 if (!((class >> 8) == PCI_CLASS_BRIDGE_PCI)) {
106                         slotno = PCI_SLOT(PCI_DN(start->child)->devfn);
107                         pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
108                         return;
109                 }
110         }
111 
112         /* Iterate all siblings */
113         for_each_child_of_node(start, dn) {
114                 class = 0;
115 
116                 if (!of_property_read_u32(start->child, "class-code", &class)) {
117                         /* Call of pci_scan_slot on each sibling-nodes/bridge-ports */
118                         if ((class >> 8) == PCI_CLASS_BRIDGE_PCI) {
119                                 slotno = PCI_SLOT(PCI_DN(dn)->devfn);
120                                 pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
121                         }
122                 }
123         }
124 }
125 
126 /**
127  * pci_hp_add_devices - adds new pci devices to bus
128  * @bus: the indicated PCI bus
129  *
130  * This routine will find and fixup new pci devices under
131  * the indicated bus. This routine presumes that there
132  * might already be some devices under this bridge, so
133  * it carefully tries to add only new devices.  (And that
134  * is how this routine differs from other, similar pcibios
135  * routines.)
136  */
137 void pci_hp_add_devices(struct pci_bus *bus)
138 {
139         int mode, max;
140         struct pci_dev *dev;
141         struct pci_controller *phb;
142         struct device_node *dn = pci_bus_to_OF_node(bus);
143 
144         phb = pci_bus_to_host(bus);
145 
146         mode = PCI_PROBE_NORMAL;
147         if (phb->controller_ops.probe_mode)
148                 mode = phb->controller_ops.probe_mode(bus);
149 
150         if (mode == PCI_PROBE_DEVTREE) {
151                 /* use ofdt-based probe */
152                 of_rescan_bus(dn, bus);
153         } else if (mode == PCI_PROBE_NORMAL &&
154                    dn->child && PCI_DN(dn->child)) {
155                 /*
156                  * Use legacy probe. In the partial hotplug case, we
157                  * probably have grandchildren devices unplugged. So
158                  * we don't check the return value from pci_scan_slot() in
159                  * order for fully rescan all the way down to pick them up.
160                  * They can have been removed during partial hotplug.
161                  */
162                 traverse_siblings_and_scan_slot(dn, bus);
163                 max = bus->busn_res.start;
164                 /*
165                  * Scan bridges that are already configured. We don't touch
166                  * them unless they are misconfigured (which will be done in
167                  * the second scan below).
168                  */
169                 for_each_pci_bridge(dev, bus)
170                         max = pci_scan_bridge(bus, dev, max, 0);
171 
172                 /* Scan bridges that need to be reconfigured */
173                 for_each_pci_bridge(dev, bus)
174                         max = pci_scan_bridge(bus, dev, max, 1);
175         }
176         pcibios_finish_adding_to_bus(bus);
177 }
178 EXPORT_SYMBOL_GPL(pci_hp_add_devices);
179 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php